package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.extra.ftp.Ftp;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zmj.sy.mom.srv.aps.bean.dto.feign.Ltk.LtkPushTokenDto;
import com.zmj.sy.mom.srv.aps.bean.dto.feign.Ltk.LtkResultResDto;
import com.zmj.sy.mom.srv.aps.bean.dto.feign.Ltk.LtkSelectResDto;
import com.zmj.sy.mom.srv.aps.bean.entity.log.LogNestExce;
import com.zmj.sy.mom.srv.aps.bean.entity.mes.*;
import com.zmj.sy.mom.srv.aps.bean.entity.order.*;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.DictData;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.LogApi;
import com.zmj.sy.mom.srv.aps.bean.entity.third.*;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseIdReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BasePageResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.lantek.*;
import com.zmj.sy.mom.srv.aps.bean.vo.mesNest.MesReceiveNestPartReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.mesNest.MesReceiveNestPlateReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.newNest.*;
import com.zmj.sy.mom.srv.aps.bean.vo.part.PartPngUrlVo;
import com.zmj.sy.mom.srv.aps.bean.vo.plate.UpdateNxolpstatusVo;
import com.zmj.sy.mom.srv.aps.bean.vo.sinocam.*;
import com.zmj.sy.mom.srv.aps.bean.vo.texturereplace.TextureReplaceSelectReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.texturereplace.TextureReplaceSelectResVo;
import com.zmj.sy.mom.srv.aps.config.ProjectConfig;
import com.zmj.sy.mom.srv.aps.feign.ApsMesFeign;
import com.zmj.sy.mom.srv.aps.feign.LantekApiClient;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.*;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Service
public class SinoCamService {

    private final ApsWorkDetailMapper apsWorkDetailMapper;
    private final ApsWorkOrderMapper apsWorkOrderMapper;
    private final SinoCamPushDrawingMapper sinoCamPushDrawingMapper;
    private final SinoCamPushPlanMapper sinoCamPushPlanMapper;
    private final SinoCamReceiveNestNestMapper sinoCamReceiveNestNestMapper;
    private final SinoCamReceiveNestPartMapper sinoCamReceiveNestPartMapper;
    private final SinoCamReceiveNestPlateMapper sinoCamReceiveNestPlateMapper;
    private final SinoCamReceiveNestExcessMapper sinoCamReceiveNestExcessMapper;
    private final SinoCamReceiveNestMoveMapper sinoCamReceiveNestMoveMapper;
    private final SinoCamReceiveNestCheckMapper sinoCamReceiveNestCheckMapper;
    private final OrderMapper orderMapper;
    private final ApsOrderMapper apsOrderMapper;
    private final PlateMapper plateMapper;
    private final OrderPartMapper orderPartMapper;
    private final ProjectConfig projectConfig;
    private final WmsPlatePickMapper wmsPlatePickMapper;
    private final HexagonNestOldUtils hexagonNestOldUtils;
    private final ImportMbdDxfMapper importMbdDxfMapper;
    private final LantekApiClient lantekApiClient;
    private final DictDataMapper dictDataMapper;
    private final WorkDetailTaskMapper workDetailTaskMapper;
    private final PlatePhaseMapper platePhaseMapper;
    private final ApsMesFeign apsMesFeign;
    private final LogNestExceMapper logNestExceMapper;
    private final HexagonPackagePushMapper hexagonPackagePushMapper;
    private final MesNestPartMapper mesNestPartMapper;
    private final WorkRecordMapper workRecordMapper;
    private final PartUtilService partUtilService;
    private final ObjectMapper objectMapper;
    private final LogApiUtils logApiUtils;

    @Value("${project.feign.dxf-download}")
    private String dxfDownload;

    @Value("${project.ftp.url}")
    // FTP地址
    private String ftpUrl;

    @Value("${project.ftp.port}")
    // FTP端口
    private Integer ftpPort;

    @Value("${project.ftp.user}")
    // FTP账号
    private String ftpUser;

    @Value("${project.ftp.password}")
    // FTP密码
    private String ftpPassword;

    @Value("${project.ftp.charset-name}")
    // FTP编码
    private String ftpCharsetName;

    @Value("${project.feign.mes-url-png}")
    private String mesPNG;

    public void pushMesMK(BaseIdReqVo reqVo) {
        // 获取需要切割的工序
        List<String> phaseCodeList = projectConfig.getCuttingProcess();

        // 获取所有需要切割的零件
        List<ApsWorkDetail> apsWorkDetailList = apsWorkDetailMapper.lambdaQuery()
                .eq(ApsWorkDetail::getOrderId, reqVo.getId())
                .eq(ApsWorkDetail::getStatus, 2)
                .eq(ApsWorkDetail::getType, 2)
                .in(ApsWorkDetail::getPhaseCode, phaseCodeList)
                .list();

        if (CollUtil.isEmpty(apsWorkDetailList)) {
            return ;
        }

        hexagonNestOldUtils.pushMesMK(reqVo, apsWorkDetailList);
    }

    public BasePageResVo<SinoCamPlateListResVo> plateList(SinoCamPlateListReqVo reqVo) {
        QueryWrapper<SinoCamReceiveNestPlate> query = Wrappers.query();
        if (reqVo.getSourceCode() == null || reqVo.getSourceCode().equalsIgnoreCase("erp")) {
            query.eq("nest.version_brief", "V2");
        } else {
            query.eq("nest.version_brief", "V1");
        }

        query.ge(StringUtils.hasText(reqVo.getEndDate()), "nest.modify_date_time", reqVo.getStartDate());
        query.le(StringUtils.hasText(reqVo.getEndDate()), "nest.modify_date_time", reqVo.getEndDate());

        Page<SinoCamPlateListResVo> page = sinoCamReceiveNestPlateMapper.find(reqVo.toPage(), query);

        BasePageResVo<SinoCamPlateListResVo> res = BasePageResVo.of(page, SinoCamPlateListResVo.class);

        for (SinoCamPlateListResVo datum : res.getData()) {
            datum.setStockAmount(new BigDecimal(1));
            datum.setPurchaseAmount(new BigDecimal(1));
            if (StringUtils.hasText(datum.getNestDateStr())) {
                datum.setNestDate(LocalDate.parse(datum.getNestDateStr(), DatePattern.NORM_DATETIME_FORMATTER));
            }
        }

        return res;
    }

    public List<LantekPushSelectListVo> pushSelect(BaseIdReqVo reqVo) {

        List<LantekPushSelectListVo> list = new ArrayList<>();
        List<ApsOrder> apsOrders = apsOrderMapper.lambdaQuery().eq(ApsOrder::getOrderId, reqVo.getId()).list();
        for (ApsOrder apsOrder : apsOrders) {
            LantekPushSelectListVo vo = new LantekPushSelectListVo();
            vo.setId(apsOrder.getId());
            vo.setConstructNo(apsOrder.getConstructNo());
            vo.setCustomerName(apsOrder.getCustomerName());
            vo.setMaterCode(apsOrder.getMaterCode());
            vo.setSeq(apsOrder.getSeq());
            vo.setDeliveryDate(apsOrder.getDeliveryDate());
            if (apsOrder.getOrderStatus() == 6) {
                vo.setStatus(0);
            } else {
                vo.setStatus(1);
            }
            list.add(vo);
        }
        return list;
    }

    public BasePageResVo<PushPartInfoResVo> pushPartInfoDetail(PushStateReqVo reqVo) {
        // 零件总数
        BigDecimal totalCount = apsWorkDetailMapper.getTotal(reqVo.getOrderId());
        if (totalCount == null) {
            throw SyExceptionUtils.e("未进行排产:{}", reqVo.getOrderId());
        }
        // 已推送零件数量
        BigDecimal pushCount = sinoCamPushPlanMapper.getPushCount(reqVo.getOrderId());
        if (pushCount == null) {
            pushCount = BigDecimal.ZERO;
        }
        // 尚未推送零件数量
        BigDecimal noPushCount = totalCount.setScale(0, RoundingMode.HALF_UP).subtract(pushCount.setScale(0, RoundingMode.HALF_UP));
        // 获取切割工序
        List<String> phaseCodeList = projectConfig.getCuttingProcess();
        QueryWrapper<ApsWorkDetail> qw = Wrappers.query();
        qw.in("awd.phase_code", phaseCodeList);
        qw.eq("o.id", reqVo.getOrderId());
        if (reqVo.getStatus() != null) {
            if (reqVo.getStatus() == 1) {
                qw.isNull("tsp.plan_amount");
            }
            if (reqVo.getStatus() == 2) {
                qw.eq("tsp.status", 4);
            }
            if (reqVo.getStatus() == 3) {
                qw.eq("tsp.status", 5);
            }
        }
        Page<PushPartInfoResVo> voPage = apsWorkDetailMapper.pushPartInfoDetailNext(reqVo.toPage(), qw);
        for (PushPartInfoResVo vo : voPage.getRecords()) {
            if (vo.getTexture() == null || vo.getThickness() == null) {
                String[] split = vo.getStandards().split("δ");
                vo.setTexture(split[0]);
                vo.setThickness(Integer.valueOf(split[1]));
            }
            vo.setPackageCode(PkgUtils.gen(vo.getPackageNum()));
            if (vo.getPushCount() == null) {
                vo.setStatus(1);
            } else {
                if (vo.getPushStatus() == 4) {
                    vo.setStatus(2);
                } else if (vo.getPushStatus() == 5) {
                    vo.setStatus(3);
                }
            }
            vo.setCount(totalCount.setScale(0, RoundingMode.HALF_UP) + "/" + pushCount.setScale(0, RoundingMode.HALF_UP) + "/" + noPushCount);
        }
        return BasePageResVo.of(voPage, PushPartInfoResVo.class);
    }

    public List<PushSeqDetailResVo> pushSeqDetail(PushStateReqVo reqVo) {
        // 新建返回 List
        List<PushSeqDetailResVo> voList = new ArrayList<>();
        // 查询包次列表
        LambdaQueryWrapper<ApsOrder> qw = new LambdaQueryWrapper<>();
        qw.eq(ApsOrder::getOrderId, reqVo.getOrderId());
        qw.orderByDesc(ApsOrder::getOrderStatus);
        List<ApsOrder> apsOrders = apsOrderMapper.selectList(qw);
        // 获取订单编号
        Order order = orderMapper.lambdaQuery().eq(Order::getId, reqVo.getOrderId()).one();
        // 获取推送零件列表
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().eq(SinoCamPushPlan::getOrderId, reqVo.getOrderId()).list();
        // 转化为 Map，以包次为 key
        Map<String, List<SinoCamPushPlan>> pushPlanMap = pushPlanList.stream().collect(Collectors.groupingBy(SinoCamPushPlan::getProcessingNo));
        for (ApsOrder apsOrder : apsOrders) {
            PushSeqDetailResVo vo = new PushSeqDetailResVo();
            vo.setOrderCode(order.getOrderCode());
            String seq = PkgUtils.gen(apsOrder.getSeq());
            vo.setPackageCode(seq);
            vo.setDeliveryTime(apsOrder.getDeliveryDate());
            if (!pushPlanMap.containsKey(seq)) {
                vo.setStatus(1);
                voList.add(vo);
                continue;
            }
            List<SinoCamPushPlan> pushPlans = pushPlanMap.get(seq);
            if (pushPlans.stream().allMatch(e -> e.getStatus() == 4)) {
                vo.setStatus(3);
            } else if (pushPlans.stream().anyMatch(e -> e.getStatus() == 5)) {
                vo.setStatus(4);
            } else {
                vo.setStatus(2);
            }
            voList.add(vo);
        }
        List<PushSeqDetailResVo> voList1 = new ArrayList<>();
        List<PushSeqDetailResVo> voList2 = new ArrayList<>();
        List<PushSeqDetailResVo> voList3 = new ArrayList<>();
        List<PushSeqDetailResVo> voList4 = new ArrayList<>();
        for (PushSeqDetailResVo vo : voList) {
            if (ObjectUtils.isEmpty(reqVo.getStatus())) {
                break;
            } else {
                if (vo.getStatus() == 1) {
                    voList1.add(vo);
                } else if (vo.getStatus() == 2) {
                    voList2.add(vo);
                } else if (vo.getStatus() == 3) {
                    voList3.add(vo);
                } else if (vo.getStatus() == 4) {
                    voList4.add(vo);
                }
            }
        }
        if (ObjectUtils.isEmpty(reqVo.getStatus())) {
            return voList;
        } else {
            if (reqVo.getStatus() == 1) {
                return voList1;
            } else if (reqVo.getStatus() == 2) {
                return voList2;
            } else if (reqVo.getStatus() == 3) {
                return voList3;
            } else if (reqVo.getStatus() == 4) {
                return voList4;
            } else {
                throw new SyException("状态参数错误");
            }
        }

    }

    public List<LantekPartInfoResVo> getPartInfo(LantekPartInfoReqVo reqVo) {
        String uniMaterCode = StringUtils.hasText(reqVo.getUniMaterCode()) ? reqVo.getUniMaterCode() : null;
        String materName = StringUtils.hasText(reqVo.getMaterName()) ? reqVo.getMaterName() : null;
        String matRef = StringUtils.hasText(reqVo.getMatRef()) ? reqVo.getMatRef() : null;
        Integer thickness = ObjectUtils.isEmpty(reqVo.getThickness()) ? null : reqVo.getThickness();
        String materCode = StringUtils.hasText(reqVo.getMaterCode()) ? reqVo.getMaterCode() : null;
        String factoryCode = StringUtils.hasText(reqVo.getFactoryCode()) ? reqVo.getFactoryCode() : null;
        String constructNo = StringUtils.hasText(reqVo.getConstructNo()) ? reqVo.getConstructNo() : null;
        String productCode = StringUtils.hasText(reqVo.getProductCode()) ? reqVo.getProductCode() : null;
        LtkSelectResDto ltkSelectResDto = lantekApiClient.getPartInfo(reqVo.getCurrent(), reqVo.getSize(), uniMaterCode, materName, matRef, thickness, materCode, factoryCode, constructNo, productCode, LtkPushTokenDto.TOKEN);
        if (ltkSelectResDto.getResult() == null) {
            throw SyExceptionUtils.e("获取零件信息失败：{}", materCode);
        }
        LtkResultResDto ltkResultResDto = BeanUtil.copyProperties(ltkSelectResDto.getResult(), LtkResultResDto.class);
        if (ltkResultResDto.getTotal() == 0) {
            throw SyExceptionUtils.e("获取零件信息为空：{}", materCode);
        }
        List<LantekPartInfoResVo> ltkPushLoftReqDtoList = new ArrayList<>();
        for (Object resVo : ltkResultResDto.getRecords()) {
            LantekPartInfoResVo dto = BeanUtil.copyProperties(resVo, LantekPartInfoResVo.class);
            ltkPushLoftReqDtoList.add(dto);
        }

        return ltkPushLoftReqDtoList;
    }

    public List<LantekNestPlanResVo> getPlan(LantekNestPlanReqVo reqVo) {
        String factoryCode = StringUtils.hasText(reqVo.getFactoryCode()) ? reqVo.getFactoryCode() : null;
        String planId = StringUtils.hasText(reqVo.getPlanId()) ? reqVo.getPlanId() : null;
        String constructNo = StringUtils.hasText(reqVo.getConstructNo()) ? reqVo.getConstructNo() : null;
        String uniMaterCode = StringUtils.hasText(reqVo.getUniMaterCode()) ? reqVo.getUniMaterCode() : null;
        String packageCode = StringUtils.hasText(reqVo.getPackageCode()) ? reqVo.getPackageCode() : null;
        String materName = StringUtils.hasText(reqVo.getMaterName()) ? reqVo.getMaterName() : null;
        LtkSelectResDto ltkSelectResDto = lantekApiClient.getPlan(reqVo.getCurrent(), reqVo.getSize(), factoryCode, planId, constructNo, uniMaterCode, packageCode, materName, LtkPushTokenDto.TOKEN);
        if (ltkSelectResDto.getResult() == null) {
            throw SyExceptionUtils.e("获取零件计划失败：{}", constructNo);
        }
        LtkResultResDto ltkResultResDto = BeanUtil.copyProperties(ltkSelectResDto.getResult(), LtkResultResDto.class);
        List<LantekNestPlanResVo> lantekNestPlanResVoList = new ArrayList<>();
        for (Object resVo : ltkResultResDto.getRecords()) {
            LantekNestPlanResVo dto = BeanUtil.copyProperties(resVo, LantekNestPlanResVo.class);
            lantekNestPlanResVoList.add(dto);
        }
        return lantekNestPlanResVoList;
    }

    public static MultipartFile getMultipartFile(File file) {
        // 文件转化为文件流
        FileItem item = new DiskFileItemFactory().createItem("file"
                , MediaType.MULTIPART_FORM_DATA_VALUE
                , true
                , file.getName());
        try (InputStream input = new FileInputStream(file);
             OutputStream os = item.getOutputStream()) {
            // 流转移
            IOUtils.copy(input, os);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid file: " + e, e);
        }

        return new CommonsMultipartFile(item);
    }


    public LantekDrawingInfoResVo drawingAnalysis(Integer orderPartId) throws Exception {
        // 取材质、厚度、图纸地址
        OrderPart orderPart = orderPartMapper.lambdaQuery().eq(OrderPart::getId, orderPartId).one();
        String plmId = orderPart.getPlmId();
        String code = "";
        if (plmId.endsWith("_170")) {
            code = plmId.substring(0, plmId.indexOf("_170"));
        } else {
            code = plmId;
        }
        ImportMbdDxf importMbdDxf = importMbdDxfMapper.lambdaQuery().eq(ImportMbdDxf::getPlmid, code).one();

        File tempFile = File.createTempFile(UUID.randomUUID().toString(), ".dxf");
        try (Ftp ftp = new Ftp(ftpUrl, ftpPort, ftpUser, ftpPassword, Charset.forName(ftpCharsetName))) {
            ftp.download(importMbdDxf.getPath(), tempFile);
        }

        MultipartFile thisFile = getMultipartFile(tempFile);

        LtkSelectResDto ltkSelectResDto = lantekApiClient.drawingAnalysis(thisFile, orderPart.getTexture(), orderPart.getThickness().setScale(0, RoundingMode.HALF_UP).intValue(), LtkPushTokenDto.TOKEN);
        LantekDrawingInfoResVo lantekDrawingInfoResVo = new LantekDrawingInfoResVo();
        if (ltkSelectResDto.getResult() == null) {
            throw SyExceptionUtils.e("零件信息解析失败：{}", plmId + ltkSelectResDto.getMessage());
        }
        lantekDrawingInfoResVo = BeanUtil.copyProperties(ltkSelectResDto.getResult(), LantekDrawingInfoResVo.class);
        orderPart.setLength(lantekDrawingInfoResVo.getLength());
        orderPart.setWidth(lantekDrawingInfoResVo.getWidth());
        orderPart.setArea(lantekDrawingInfoResVo.getArea());
        orderPart.setNestWeight(lantekDrawingInfoResVo.getNetWeight());
        orderPartMapper.updateById(orderPart);
        return lantekDrawingInfoResVo;
    }

    public void exchangePNG(Integer orderPartId) throws Exception {
        // 取材质、厚度、图纸地址
        OrderPart orderPart = orderPartMapper.lambdaQuery().eq(OrderPart::getId, orderPartId).one();
        String plmId = orderPart.getPlmId();
        String code = "";
        if (plmId.endsWith("_170")) {
            code = plmId.substring(0, plmId.indexOf("_170"));
        } else {
            code = plmId;
        }
        ImportMbdDxf importMbdDxf = importMbdDxfMapper.lambdaQuery().eq(ImportMbdDxf::getPlmid, code).one();

        File tempFile = File.createTempFile(UUID.randomUUID().toString(), ".dxf");
        try (Ftp ftp = new Ftp(ftpUrl, ftpPort, ftpUser, ftpPassword, Charset.forName(ftpCharsetName))) {
            ftp.download(importMbdDxf.getPath(), tempFile);
        }
        MultipartFile thisFile = getMultipartFile(tempFile);
        byte[] responseFile = lantekApiClient.exchangePNG(thisFile, LtkPushTokenDto.TOKEN);

        String path = FileStorageUtils.getFilePath(FileStorageUtils.PART_PNG_TYPE);
        FileUtils.writeByteArrayToFile(new File(path), responseFile);
        orderPart.setPngUrl(path);
        orderPart.setDrawStatus(3);
        orderPartMapper.updateById(orderPart);
    }

    public void exchangePDF(Integer orderPartId) throws Exception {
        // 取材质、厚度、图纸地址
        OrderPart orderPart = orderPartMapper.lambdaQuery().eq(OrderPart::getId, orderPartId).one();
        String plmId = orderPart.getPlmId();
        String code = "";
        if (plmId.endsWith("_170")) {
            code = plmId.substring(0, plmId.indexOf("_170"));
        } else {
            code = plmId;
        }
        ImportMbdDxf importMbdDxf = importMbdDxfMapper.lambdaQuery().eq(ImportMbdDxf::getPlmid, code).one();

        File tempFile = File.createTempFile(UUID.randomUUID().toString(), ".dxf");
        try (Ftp ftp = new Ftp(ftpUrl, ftpPort, ftpUser, ftpPassword, Charset.forName(ftpCharsetName))) {
            ftp.download(importMbdDxf.getPath(), tempFile);
        }
        MultipartFile thisFile = getMultipartFile(tempFile);
        byte[] responseFile = lantekApiClient.exchangePDF(thisFile, LtkPushTokenDto.TOKEN);

        String path = FileStorageUtils.getFilePath(FileStorageUtils.PART_PDF_TYPE);

        FileUtils.writeByteArrayToFile(new File(path), responseFile);
    }

    public List<String> textureReplace(String texture) {
        List<String> list = new LinkedList<>();
        // 查询所有以高代低可用的材质
        LambdaQueryWrapper<DictData> qw = new LambdaQueryWrapper<>();
        qw.orderByDesc(DictData::getDictValue);
        List<DictData> listData = dictDataMapper.findTexture(qw);

        Map<String, String> mapData = listData.stream().collect(Collectors.toMap(DictData::getDictLabel, DictData::getDictValue));
        // 判断可供本材质使用的高材质
        for (DictData data : listData) {
            /*if (Integer.parseInt(mapData.get(texture)) > Integer.parseInt(mapData.get(data.getDictLabel()))) {
                continue;
            }*/
            list.add(data.getDictLabel());
        }
        return list;
    }

    public List<TextureReplaceSelectResVo> textureReplaceSelect(TextureReplaceSelectReqVo reqVo) {
        List<TextureReplaceSelectResVo> list = sinoCamPushDrawingMapper.textureReplaceSelect(reqVo.getNestPlanId());
        for (TextureReplaceSelectResVo vo : list) {
            vo.setWaitCount(vo.getTotalCount().subtract(vo.getFinishCount()));
            if (StringUtils.hasText(vo.getReplaceTexture())) {
                vo.setTexture(vo.getReplaceTexture());
            }
        }
        return list;
    }

    public boolean checkPlateReceive(String nestId) {
        SinoCamReceiveNestNest nestNest = sinoCamReceiveNestNestMapper.lambdaQuery().eq(SinoCamReceiveNestNest::getNestId, nestId).one();
        if (ObjectUtils.isEmpty(nestNest)) {
            return false;
        }
        List<SinoCamReceiveNestPlate> list = sinoCamReceiveNestPlateMapper.lambdaQuery().eq(SinoCamReceiveNestPlate::getReceiveNestId, nestNest.getReceiveNestId()).list();
        if (ObjectUtils.isEmpty(list)) {
            return false;
        }
        return true;
    }

    public BaseResVo splitPlan() {
        List<ApsWorkDetail> list = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getPhaseCode, "PZ").list();
        for (ApsWorkDetail detail : list) {
            apsWorkSplit(detail.getId());
        }
        return BaseResVo.ok();
    }

    public void apsWorkSplit(Integer apsWorkDetailId) {
        ApsWorkDetail apsWorkDetail = apsWorkDetailMapper.selectById(apsWorkDetailId);
        BigDecimal totalCount = apsWorkDetail.getTotalCount();
        int totalCountInt = totalCount.intValue();
        ApsWorkDetail add = BeanUtil.copyProperties(apsWorkDetail, ApsWorkDetail.class);
        add.setTotalCount(BigDecimal.ONE.setScale(2, RoundingMode.HALF_UP));
        add.setStatus(2);
        add.setUniqueCode(null);
        if (apsWorkDetail.getFinishCount().compareTo(BigDecimal.ONE) == 0) {
            add.setFinishCount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
        }
        apsWorkDetail.setTotalCount(BigDecimal.ONE.setScale(2, RoundingMode.HALF_UP));
        apsWorkDetailMapper.updateById(apsWorkDetail);
        for (int i = 0; i < totalCountInt - 1; i++) {
            add.setType(2);
            apsWorkDetailMapper.insert(add);
        }
    }

    public void fillDxf() {
        List<OrderPart> orderParts = orderPartMapper.lambdaQuery().eq(OrderPart::getMaterType, "Platepart").list();
        List<ImportMbdDxf> mbdDxfList = importMbdDxfMapper.lambdaQuery().in(ImportMbdDxf::getPlmid, orderParts.stream().map(OrderPart::getPlmId).collect(Collectors.toList())).list();
        Map<String, ImportMbdDxf> mbdDxfMap = mbdDxfList.stream().collect(Collectors.toMap(ImportMbdDxf::getPlmid, Function.identity()));
        for (OrderPart orderPart : orderParts) {
            ImportMbdDxf dxf = mbdDxfMap.get(orderPart.getPlmId());
            if (dxf != null) {
                orderPart.setDxfUrl(dxf.getPath());
                orderPartMapper.updateById(orderPart);
            }
        }
    }

    public void clearNestResultInfo(String nestId) {
        SinoCamReceiveNestNest nestNest = sinoCamReceiveNestNestMapper.lambdaQuery().eq(SinoCamReceiveNestNest::getNestId, nestId).one();
        if (nestNest == null) {
            return;
        }

        // 套料图号检查是否为双板，并且查询领料单表是否为下发过领料单的
        List<WmsPlatePick> receivePlateList = wmsPlatePickMapper.lambdaQuery().eq(WmsPlatePick::getNestId, nestId).list();
        boolean flag = false;

        for (WmsPlatePick pick : receivePlateList) {
            // 定时任务拉取回的数据需要清除。
            if (!StringUtils.hasText(pick.getPickingListNo())) {
                flag = false;
                continue;
            }
            // MES 中钢板套料结果已经删除，或者 MES 中钢板套料图号已发生改变的需要清除。
            ReceiveNestPlateReqVo vo = apsMesFeign.checkNestPlate(pick.getMaterialCode());
            if (ObjectUtils.isEmpty(vo) || !vo.getNestId().equals(nestId)) {
                flag = false;
                continue;
            }
            flag = true;
        }

        if (flag) {
            return;
        }

        sinoCamReceiveNestNestMapper.deleteMesNest(nestNest.getId());

        List<SinoCamReceiveNestPlate> nestPlateList = sinoCamReceiveNestPlateMapper.lambdaQuery().eq(SinoCamReceiveNestPlate::getNestId, nestId).list();
        if (CollUtil.isNotEmpty(nestPlateList)) {
            List<String> plateCodeList = nestPlateList.stream().map(SinoCamReceiveNestPlate::getStockListNo).collect(Collectors.toList());
            List<ApsWorkDetail> apsWorkDetailList = apsWorkDetailMapper.lambdaQuery().in(ApsWorkDetail::getMaterNo, plateCodeList).list();
            List<PlatePhase> platePhaseList = platePhaseMapper.lambdaQuery().in(PlatePhase::getPlateCode, plateCodeList).list();
            for (SinoCamReceiveNestPlate a : nestPlateList) {
                sinoCamReceiveNestPlateMapper.deleteMesNest(a.getId());
            }
            for (ApsWorkDetail a : apsWorkDetailList) {
                apsWorkDetailMapper.deleteMesNest(a.getId());
            }
            for (PlatePhase a : platePhaseList) {
                platePhaseMapper.deleteMesNest(a.getId());
            }
        }

        List<SinoCamReceiveNestPart> nestPartList = sinoCamReceiveNestPartMapper.lambdaQuery().eq(SinoCamReceiveNestPart::getNestId, nestId).list();
        if (CollUtil.isNotEmpty(nestPartList)) {
            List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery()
                    .in(SinoCamPushPlan::getNestPlanId, nestPartList.stream().map(SinoCamReceiveNestPart::getNestPlanId).collect(Collectors.toList())).list();
            Map<String, SinoCamPushPlan> pushPlanMap = pushPlanList.stream().collect(Collectors.toMap(SinoCamPushPlan::getNestPlanId, Function.identity()));
            // 修改：零件推送表[pushplan]，修改零件套料回推数量
            for (SinoCamReceiveNestPart part : nestPartList) {
                SinoCamPushPlan pp = pushPlanMap.get(part.getNestPlanId());
                pp.setPlanFinishAmount(pp.getPlanFinishAmount().subtract(BigDecimal.valueOf(part.getQuantity())));
                pp.setConsumeStatus(0);
                sinoCamPushPlanMapper.updateById(pp);
            }
            for (SinoCamReceiveNestPart a : nestPartList) {
                sinoCamReceiveNestPartMapper.deleteMesNest(a.getId());
            }
        }

        // 删除：接收结果表（nest，plate，part，move，excess[可能不存在]）
        // 钢板信息表[mes_plate]，钢板领料表[mes_plate_pick]，钢板任务表[mes_work_detail_task]，钢板计划表[aps_work_detail]，钢板工序表[mes_plate_phase]
        List<SinoCamReceiveNestMove> nestMoveList = sinoCamReceiveNestMoveMapper.lambdaQuery().eq(SinoCamReceiveNestMove::getNestId, nestId).list();
        if (CollUtil.isNotEmpty(nestMoveList)) {
            for (SinoCamReceiveNestMove a : nestMoveList) {
                sinoCamReceiveNestMoveMapper.deleteMesNest(a.getId());
            }
        }

        List<SinoCamReceiveNestExcess> nestExcessList = sinoCamReceiveNestExcessMapper.lambdaQuery().eq(SinoCamReceiveNestExcess::getNestId, nestId).list();
        if (CollUtil.isNotEmpty(nestExcessList)) {
            for (SinoCamReceiveNestExcess a : nestExcessList) {
                sinoCamReceiveNestExcessMapper.deleteMesNest(a.getId());
            }
        }

        List<Plate> plateList = plateMapper.lambdaQuery().eq(Plate::getNestId, nestId).list();
        if (CollUtil.isNotEmpty(plateList)) {
            for (Plate a : plateList) {
                plateMapper.deleteMesNest(a.getId());
            }
        }

        List<WmsPlatePick> platePickList = wmsPlatePickMapper.lambdaQuery().eq(WmsPlatePick::getNestId, nestId).list();
        if (CollUtil.isNotEmpty(platePickList)) {
            for (WmsPlatePick a : platePickList) {
                wmsPlatePickMapper.deleteMesNest(a.getId());
            }
        }

        List<WorkDetailTask> workDetailTaskList = workDetailTaskMapper.lambdaQuery().eq(WorkDetailTask::getNestId, nestId).list();
        if (CollUtil.isNotEmpty(workDetailTaskList)) {
            for (WorkDetailTask a : workDetailTaskList) {
                workDetailTaskMapper.deleteMesNest(a.getId());
            }
        }

    }

    public void clearNestResultInfoPlate(String plateCode) {

        SinoCamReceiveNestPlate nestPlate = sinoCamReceiveNestPlateMapper.lambdaQuery().eq(SinoCamReceiveNestPlate::getStockListNo, plateCode).one();
        if (ObjectUtils.isEmpty(nestPlate)) {
            return;
        }

        // 先删除钢板上的零件信息
        List<SinoCamReceiveNestPart> nestPartList = sinoCamReceiveNestPartMapper.lambdaQuery().eq(SinoCamReceiveNestPart::getPlateCode, plateCode).list();

        WorkDetailTask yCTask = workDetailTaskMapper.lambdaQuery()
                .eq(WorkDetailTask::getPlmid, plateCode)
                .eq(WorkDetailTask::getType, 1)
                .eq(WorkDetailTask::getPhaseCode, WorkshopProp.YC_PHASE_CODE)
                .one();
        if (!ObjectUtils.isEmpty(yCTask) && yCTask.getStatus() == 3) {
            for (SinoCamReceiveNestPart nestPart : nestPartList) {
                ApsWorkDetail qgApsWorkDetail = apsWorkDetailMapper.lambdaQuery()
                        .eq(ApsWorkDetail::getId, nestPart.getNestPlanId())
                        .one();
                if (!ObjectUtils.isEmpty(qgApsWorkDetail)) {
                    ApsWorkDetail ycWorkDetail = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getType, 2)
                            .eq(ApsWorkDetail::getApsWorkOrderId, qgApsWorkDetail.getApsWorkOrderId())
                            .eq(ApsWorkDetail::getPhaseCode, WorkshopProp.YC_PHASE_CODE).last(" LIMIT 1 ").one();

                    if (!ObjectUtils.isEmpty(ycWorkDetail)) {
                        apsWorkDetailMapper.lambdaUpdate().eq(ApsWorkDetail::getId, ycWorkDetail.getId())
                                .set(ycWorkDetail.getFinishCount().subtract(new BigDecimal(nestPart.getQuantity())).compareTo(ycWorkDetail.getTotalCount()) < 0, ApsWorkDetail::getStatus, 3)
                                .setSql("finish_count=finish_count-" + nestPart.getQuantity()).update();
                    }
                }

            }

        }
        //删除报工记录
        List<WorkRecord> recordList = workRecordMapper.lambdaQuery().eq(WorkRecord::getPalletNumber, plateCode).eq(WorkRecord::getType, 2)
                .eq(WorkRecord::getPhaseCode, WorkshopProp.YC_PHASE_CODE).list();
        for (WorkRecord r : recordList) {
            workRecordMapper.deleteWithId(r.getId());
        }

        WorkDetailTask llTask = workDetailTaskMapper.lambdaQuery()
                .eq(WorkDetailTask::getPlmid, plateCode)
                .eq(WorkDetailTask::getType, 1)
                .eq(WorkDetailTask::getPhaseCode, WorkshopProp.LL_PHASE_CODE)
                .one();
        if (!ObjectUtils.isEmpty(llTask) && llTask.getStatus() == 3) {
            for (SinoCamReceiveNestPart nestPart : nestPartList) {
                ApsWorkDetail qgWrkDetail = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getId, nestPart.getNestPlanId()).one();
                ApsWorkDetail llApsWorkDetail = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getApsWorkOrderId, qgWrkDetail.getApsWorkOrderId())
                        .eq(ApsWorkDetail::getType, 2).eq(ApsWorkDetail::getPhaseCode, WorkshopProp.LL_PHASE_CODE).last("  LIMIT 1 ").one();
                if (!org.apache.commons.lang3.ObjectUtils.isEmpty(llApsWorkDetail)) {
                    //更新零件的计划信息
                    apsWorkDetailMapper.lambdaUpdate().eq(ApsWorkDetail::getId, llApsWorkDetail.getId())
                            .set(llApsWorkDetail.getFinishCount().subtract(new BigDecimal(nestPart.getQuantity())).compareTo(llApsWorkDetail.getTotalCount()) < 0, ApsWorkDetail::getStatus, 3)
                            .setSql("finish_count=finish_count-" + nestPart.getQuantity()).update();
                }
            }
        }

        if (CollUtil.isNotEmpty(nestPartList)) {
            List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery()
                    .in(SinoCamPushPlan::getNestPlanId, nestPartList.stream().map(SinoCamReceiveNestPart::getNestPlanId).collect(Collectors.toList())).list();
            Map<String, SinoCamPushPlan> pushPlanMap = pushPlanList.stream().collect(Collectors.toMap(SinoCamPushPlan::getNestPlanId, Function.identity()));

            for (SinoCamReceiveNestPart part : nestPartList) {
                SinoCamPushPlan pp = pushPlanMap.get(part.getNestPlanId());
                pp.setPlanFinishAmount(pp.getPlanFinishAmount().subtract(BigDecimal.valueOf(part.getQuantity())));
                pp.setConsumeStatus(0);
                sinoCamPushPlanMapper.updateById(pp);
            }
            for (SinoCamReceiveNestPart a : nestPartList) {
                sinoCamReceiveNestPartMapper.deleteMesNest(a.getId());
            }
        }

        sinoCamReceiveNestPlateMapper.deleteMesNestWithCode(plateCode);

        apsWorkDetailMapper.deleteMesNestWithCode(plateCode);

        platePhaseMapper.deleteMesNestWithCode(plateCode);

//        List<SinoCamReceiveNestPart> nestPartList = sinoCamReceiveNestPartMapper.lambdaQuery().eq(SinoCamReceiveNestPart::getPlateCode, plateCode).list();
        /*if (CollUtil.isNotEmpty(nestPartList)) {
            List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery()
                    .in(SinoCamPushPlan::getNestPlanId, nestPartList.stream().map(SinoCamReceiveNestPart::getNestPlanId).collect(Collectors.toList())).list();
            Map<String, SinoCamPushPlan> pushPlanMap = pushPlanList.stream().collect(Collectors.toMap(SinoCamPushPlan::getNestPlanId, Function.identity()));
            // 修改：零件推送表[pushplan]，修改零件套料回推数量
            for (SinoCamReceiveNestPart part : nestPartList) {
                SinoCamPushPlan pp = pushPlanMap.get(part.getNestPlanId());
                pp.setPlanFinishAmount(pp.getPlanFinishAmount().subtract(BigDecimal.valueOf(part.getQuantity())));
                pp.setConsumeStatus(0);
                sinoCamPushPlanMapper.updateById(pp);
            }
            sinoCamReceiveNestPartMapper.deleteMesNestWithCode(plateCode);
        }*/

        sinoCamReceiveNestExcessMapper.deleteMesNestWithCode(plateCode);

        plateMapper.deleteMesNestWithCode(plateCode);

        wmsPlatePickMapper.deleteMesNestWithCode(plateCode);

        workDetailTaskMapper.deleteMesNestWithCode(plateCode);

        sinoCamReceiveNestMoveMapper.deleteMesNestWithCode(nestPlate.getNestId());

        sinoCamReceiveNestNestMapper.deleteMesNestWithCode(nestPlate.getNestId());

    }

    public void clearNestResultInfoNew(NestPickingHeader reqVo) {

        List<String> nestIdList = reqVo.getNestPlateInfoList().stream().map(NestPlateInfo::getNesting).distinct().collect(Collectors.toCollection(LinkedList::new));
        List<String> plateCodeList = reqVo.getNestPlateInfoList().stream().map(NestPlateInfo::getMaterialId).distinct().collect(Collectors.toCollection(LinkedList::new));

        LogNestExce logNestExce = new LogNestExce();
        logNestExce.setAppId("MES套料领料单下发");
        logNestExce.setPlateCode("领料单");
        logNestExce.setConstructNo("G" + reqVo.getPickingListNo());
        logNestExce.setNestId("领料单");
        logNestExce.setPartId(null);
        logNestExce.setQuantity(plateCodeList.size());
        logNestExce.setNote("领料单号：" + "G" + reqVo.getPickingListNo());
        logNestExce.setInfoState(0);
        logNestExceMapper.insert(logNestExce);

        // 套料图号删除信息
        for (String n : nestIdList) {
            try {
                clearNestResultInfo(n);
            } catch (Exception e) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(null);
                logNestExce.setConstructNo(null);
                logNestExce.setNestId(n);
                logNestExce.setPartId("ALL");
                logNestExce.setQuantity(0);
                logNestExce.setNote("套料图号信息删除失败：" + n);
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
            }
        }
        // 钢板号删除信息
        for (String p : plateCodeList) {
            try {
                clearNestResultInfoPlate(p);
            } catch (Exception e) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(p);
                logNestExce.setConstructNo(null);
                logNestExce.setNestId(null);
                logNestExce.setPartId("ALL");
                logNestExce.setQuantity(0);
                logNestExce.setNote("钢板号信息删除失败：" + p);
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
            }
        }
    }

    public void checkNestResult(String plateCode, String userCode) {
        SinoCamReceiveNestPlate one = sinoCamReceiveNestPlateMapper.lambdaQuery().eq(SinoCamReceiveNestPlate::getStockListNo, plateCode).one();
        if (one == null) {
            ReceiveNestPlateReqVo plateVo = receiveNestInfoHand(plateCode);
            ReceiveNestPlateReqVo nestInfoVo = handleNestResult(plateVo);
            nestInfoVo.setPickListCode("G031392");
            nestInfoVo.setPickNo(1);
            hexagonNestOldUtils.receiveMesNew(nestInfoVo);

            String apiName = "寻回套料结果-" + userCode;
            LogApi logApi = logApiUtils.getReceiveLog("MES套料", apiName, "/sinoCam/catchLostPlate");
            // JSON转换
            String s = JsonUtils.toJsonString(nestInfoVo);
            Map<String, String> resVo = new HashMap<>();
            logApiUtils.setReqStr(logApi, s);
            String remark = "套料图号：" + plateVo.getNestId();
            logApiUtils.successAndSave(logApi, resVo, remark);

        }

    }

    @Transactional
    public void catchLostPlate(SinoCamCatchLostPlateReqVo reqVo) {
        // 清空可能存在的已有的钢板信息
        clearNestResultInfoPlate(reqVo.getPlateCode());

        List<WorkRecord> plateRecord = workRecordMapper.lambdaQuery().eq(WorkRecord::getPalletNumber, reqVo.getPlateCode()).eq(WorkRecord::getType, 1).list();
        for (WorkRecord r : plateRecord) {
            workRecordMapper.deleteWithId(r.getId());
        }

        String userCode = SySecurityUtils.getUserCode();
        // 调用检查钢板是否存在接口，寻回钢板信息，并记录日志
        checkNestResult(reqVo.getPlateCode(), userCode);
    }

    public void getPngPlmId(String plmId) {
        try {
            PartPngUrlVo vo = apsMesFeign.getPngUrl(plmId);
            if (vo != null) {
                vo.setPartPng(mesPNG + vo.getPartPng());
                orderPartMapper.lambdaUpdate().eq(OrderPart::getPlmId, plmId).set(OrderPart::getPngUrl, vo.getPartPng()).update();
            } else {
                log.info("零件图文件获取失败：{}", plmId);
            }
        } catch(Exception e) {
            log.info("零件图文件下载失败：{}", plmId);
        }
    }

    public List<String> checkPlateNotAps(List<String> list) {
        List<String> s = new ArrayList<>();
        List<SinoCamReceiveNestPlate> nestPlates = sinoCamReceiveNestPlateMapper.lambdaQuery().in(SinoCamReceiveNestPlate::getStockListNo, list).list();
        Map<String, SinoCamReceiveNestPlate> nestPlateMap = nestPlates.stream().collect(Collectors.toMap(SinoCamReceiveNestPlate::getStockListNo, Function.identity()));
        for (String a : list) {
            if (!nestPlateMap.containsKey(a)) {
                s.add(a);
            }
        }
        return s;
    }

    @Transactional
    public void receiveMesParts(MesReceiveNestPlateReqVo reqVo) {

        SinoCamReceiveNestPlate nestPlate = sinoCamReceiveNestPlateMapper.lambdaQuery().eq(SinoCamReceiveNestPlate::getStockListNo, reqVo.getPlateCode()).one();

        nestPlate.setPngUrl(mesPNG + reqVo.getPngUrl());
        sinoCamReceiveNestPlateMapper.updateById(nestPlate);

        List<String> orderCode = Arrays.asList("Z24-199Z2", "Z24-219G", "Z24-199GZ", "Z24-214G", "Z24-219ZZ", "Z24-218D1", "006-Z24-148ZY", "Z24-148G", "007-Z24-148LS", "Z24-159Z", "Z24-265ZG", "Z24-233Z", "Z24-233G", "Z24-265G", "Z24-265Z", "Z24-241G", "Z24-241Z", "Z24-258Z", "支撑", "Z24-262Z", "GZ2025-01", "Z24-285Z", "J24-170-092", "Z24-258G", "Z24-187G", "Z24-262G", "Z24-274G2", "Z24-282G", "Z24-187D1", "Z24-274G1", "Z24-130ZL2", "Z24-283Z", "Z24-283D", "Z24-187Z", "003-试板工装", "Z24-290Z", "Z24-221Z", "Z24-118Z", "Z25-005D", "Z24-118G","Z24-218Z2","Z24-258ZK","J23-170-026","Z24-276Z","J25-170-001");

        LogNestExce logNestExce = new LogNestExce();

        // 查询钢板上零件的推送计划，先锁订单，再锁零件号
        List<MesReceiveNestPartReqVo> partList = reqVo.getPart();
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery()
                .in(SinoCamPushPlan::getProductId, partList.stream().map(MesReceiveNestPartReqVo::getConstructNo).collect(Collectors.toList()))
                .in(SinoCamPushPlan::getPartId, partList.stream().map(MesReceiveNestPartReqVo::getPartId).collect(Collectors.toList()))
                .orderByAsc(SinoCamPushPlan::getProcessingNo)
                .list();
        if (pushPlanList.isEmpty()) {
            logNestExce.setAppId("MES套料");
            logNestExce.setPlateCode(reqVo.getPlateCode());
            logNestExce.setConstructNo(null);
            logNestExce.setNestId(reqVo.getNestId());
            logNestExce.setPartId("ALL");
            logNestExce.setQuantity(0);
            logNestExce.setNote("未查询到该板零件的推送计划：" + reqVo.getPlateCode());
            logNestExce.setInfoState(0);
            logNestExceMapper.insert(logNestExce);
            return;
        }

        // 施工号
        Map<String, List<SinoCamPushPlan>> pushProMap = pushPlanList.stream().collect(Collectors.groupingBy(SinoCamPushPlan::getProductId));
        Map<String, Map<String, List<SinoCamPushPlan>>> pushProPartMap = new HashMap<>();
        for (String pro : pushProMap.keySet()) {
            List<SinoCamPushPlan> pushPlanMapList = pushProMap.get(pro);
            // 零件号
            Map<String, List<SinoCamPushPlan>> pushPartMap = pushPlanMapList.stream().collect(Collectors.groupingBy(SinoCamPushPlan::getPartId));
            pushProPartMap.put(pro, pushPartMap);
        }

        SinoCamReceiveNestNest nn = sinoCamReceiveNestNestMapper.lambdaQuery().eq(SinoCamReceiveNestNest::getNestId, nestPlate.getNestId()).one();
        int scId = nn.getSinoCamId();
        int scrnId = nn.getReceiveNestId();
        // 零件
        List<MesReceiveNestPartReqVo> receiveNestParts = reqVo.getPart();
        List<SinoCamReceiveNestPart> receiveParts = new ArrayList<>();
        for (MesReceiveNestPartReqVo e : receiveNestParts) {

            if (!StringUtils.hasText(e.getConstructNo())) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(e.getPartId());
                logNestExce.setQuantity(e.getQuantity());
                logNestExce.setNote("该零件没有施工号：" + e.getPartId());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
                continue;
            }

            BigDecimal quantity = BigDecimal.valueOf(e.getQuantity()); // 当前钢板上套的数量
            List<SinoCamPushPlan> plans = null;
            // 先取施工号
            if (orderCode.contains(e.getConstructNo())) {
                Map<String, List<SinoCamPushPlan>> pushPlanProMap = pushProPartMap.get(e.getConstructNo());
                if (pushPlanProMap == null || pushPlanProMap.isEmpty()) {
                    logNestExce.setAppId("MES套料");
                    logNestExce.setPlateCode(reqVo.getPlateCode());
                    logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                    logNestExce.setNestId(reqVo.getNestId());
                    logNestExce.setPartId(e.getPartId());
                    logNestExce.setQuantity(e.getQuantity());
                    logNestExce.setNote("该零件未查询到推送计划：" + e.getPartId());
                    logNestExce.setInfoState(0);
                    logNestExceMapper.insert(logNestExce);
                    continue;
                }

                // 再取零件号
                plans = pushPlanProMap.get(e.getPartId());
                if (plans == null) {
                    logNestExce.setAppId("MES套料");
                    logNestExce.setPlateCode(reqVo.getPlateCode());
                    logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                    logNestExce.setNestId(reqVo.getNestId());
                    logNestExce.setPartId(e.getPartId());
                    logNestExce.setQuantity(e.getQuantity());
                    logNestExce.setNote("该零件未查询到推送计划：" + e.getPartId());
                    logNestExce.setInfoState(0);
                    logNestExceMapper.insert(logNestExce);
                    continue;
                }
            } else {
                plans = sinoCamPushPlanMapper.lambdaQuery()
                        .eq(SinoCamPushPlan::getMesOrderCode, e.getMesOrderCode())
                        .eq(SinoCamPushPlan::getMesPkgCode, e.getMesPkgCode())
                        .eq(SinoCamPushPlan::getPartId, e.getPartId())
                        .apply(" plan_amount <> plan_finish_amount ")
                        .orderByAsc(SinoCamPushPlan::getNeedDate)
                        .list();

                if (CollUtil.isEmpty(plans)) {
                    plans = sinoCamPushPlanMapper.lambdaQuery()
                            .eq(SinoCamPushPlan::getMesOrderCode, e.getMesOrderCode())
                            .eq(SinoCamPushPlan::getMesPkgCode, e.getMesPkgCode())
                            .eq(SinoCamPushPlan::getPartId, e.getPartId())
                            .orderByDesc(SinoCamPushPlan::getId)
                            .last(" limit 1")
                            .list();
                    if (CollUtil.isEmpty(plans)) {
                        logNestExce.setAppId("MES套料");
                        logNestExce.setPlateCode(reqVo.getPlateCode());
                        logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                        logNestExce.setNestId(reqVo.getNestId());
                        logNestExce.setPartId(e.getPartId());
                        logNestExce.setQuantity(e.getQuantity());
                        logNestExce.setNote("该零件未查询到推送计划：" + e.getPartId());
                        logNestExce.setInfoState(0);
                        logNestExceMapper.insert(logNestExce);
                        continue;
                    }
                }

            }

            for (int index = 0; index < plans.size(); index++) {
                SinoCamPushPlan plan = plans.get(index);
                log.info("原始数据:{}", JsonUtils.toJsonString(plan));
                if (orderCode.contains(e.getConstructNo())) {
                    if ((index != plans.size() - 1 && plan.getPlanFinishAmount().compareTo(plan.getPlanAmount()) >= 0) || quantity.compareTo(BigDecimal.ZERO) <= 0) {
                        continue;
                    }
                } else {
                    if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
                        continue;
                    }
                }
                BigDecimal planAmount = plan.getPlanAmount(); // 该计划的需要数量
                BigDecimal planFinishAmount = plan.getPlanFinishAmount(); // 该计划已经套的数量
                BigDecimal amount = planAmount.subtract(planFinishAmount); // 该计划当前所需差值
                if (quantity.compareTo(amount) < 0) {
                    // 该钢板所套数量小于该计划当前的差值，所有数量全部归到该条数据
                    SinoCamReceiveNestPart part = MkBeanUtils.copyProperties(e, SinoCamReceiveNestPart.class);
                    part.setSinoCamId(scId);
                    part.setReceiveNestId(scrnId);
                    part.setNestId(nn.getNestId());
                    part.setNestPlanId(plan.getNestPlanId());
                    part.setPartId(plan.getPartId());
                    part.setPartName(e.getPartName());
                    part.setQuantity(quantity.intValue());
                    part.setNetWeight(e.getNetWeight());
                    part.setArea(e.getArea() != null ? e.getArea() : BigDecimal.ZERO);
                    part.setRectangleArea(e.getRectangleArea() != null ? e.getRectangleArea() : BigDecimal.ZERO);
                    part.setRequireFactoryId(e.getFactoryCode());
                    part.setWidth(e.getWidth());
                    part.setLength(e.getLength());
                    if (e.getThickness() == null || e.getThickness().compareTo(BigDecimal.ZERO) == 0) {
                        part.setThickness(reqVo.getThickness());
                    } else {
                        part.setThickness(e.getThickness());
                    }
                    part.setPartMapUrl(mesPNG + e.getPngUrl());
                    part.setPlateCode(e.getPlateCode());
                    part.setSortingCount(0);// 分拣数量
                    part.setUniCode(plan.getUniMaterCode());
                    part.setSortState(0);
                    part.setOrderId(plan.getOrderId());
                    part.setWorkOrderCode(e.getWorkOrderCode());
                    part.setMesOrderCode(e.getMesOrderCode());
                    part.setMesPkgCode(e.getMesPkgCode());
                    part.setMesLineId(e.getLineId());
                    plan.setPlanFinishAmount(planFinishAmount.add(quantity));
                    quantity = BigDecimal.ZERO;
                    receiveParts.add(part);
                    plan.setStatus(4);
                    plan.setErrorMsg("已回填数据。");
                    log.info("目标数据:{}", JsonUtils.toJsonString(plan));
                    sinoCamPushPlanMapper.updateById(plan);
                } else if (quantity.compareTo(amount) == 0) {
                    // 该钢板所套数量等于该计划当前的差值，所有数量全部归到该条数据，并且修改状态为填充完成
                    SinoCamReceiveNestPart part = MkBeanUtils.copyProperties(e, SinoCamReceiveNestPart.class);
                    part.setSinoCamId(scId);
                    part.setReceiveNestId(scrnId);
                    part.setNestId(nn.getNestId());
                    part.setNestPlanId(plan.getNestPlanId());
                    part.setPartId(plan.getPartId());
                    part.setPartName(e.getPartName());
                    part.setQuantity(quantity.intValue());
                    part.setNetWeight(e.getNetWeight());
                    part.setArea(e.getArea() != null ? e.getArea() : BigDecimal.ZERO);
                    part.setRectangleArea(e.getRectangleArea() != null ? e.getRectangleArea() : BigDecimal.ZERO);
                    part.setRequireFactoryId(e.getFactoryCode());
                    part.setWidth(e.getWidth());
                    part.setLength(e.getLength());
                    if (e.getThickness() == null || e.getThickness().compareTo(BigDecimal.ZERO) == 0) {
                        part.setThickness(reqVo.getThickness());
                    } else {
                        part.setThickness(e.getThickness());
                    }
                    part.setPartMapUrl(mesPNG + e.getPngUrl());
                    part.setPlateCode(e.getPlateCode());
                    part.setSortingCount(0);// 分拣数量
                    part.setUniCode(plan.getUniMaterCode());
                    part.setSortState(0);
                    part.setOrderId(plan.getOrderId());
                    part.setWorkOrderCode(e.getWorkOrderCode());
                    part.setMesOrderCode(e.getMesOrderCode());
                    part.setMesPkgCode(e.getMesPkgCode());
                    part.setMesLineId(e.getLineId());
                    plan.setPlanFinishAmount(planFinishAmount.add(quantity));
                    quantity = BigDecimal.ZERO;
                    receiveParts.add(part);
                    plan.setConsumeStatus(1);
                    plan.setStatus(4);
                    plan.setErrorMsg("已回填数据。");
                    log.info("目标数据:{}", JsonUtils.toJsonString(plan));
                    sinoCamPushPlanMapper.updateById(plan);
                } else if (quantity.compareTo(amount) > 0) {
                    // 该钢板所套数量大于该计划当前的差值，填充该数据所有差值，并且修改状态为填充完成，将该板剩余数量填充下一条数据
                    SinoCamReceiveNestPart part = MkBeanUtils.copyProperties(e, SinoCamReceiveNestPart.class);
                    part.setSinoCamId(scId);
                    part.setReceiveNestId(scrnId);
                    part.setNestId(nn.getNestId());
                    part.setNestPlanId(plan.getNestPlanId());
                    part.setPartId(e.getPartId());
                    part.setPartName(e.getPartName());
                    BigDecimal partQuantity = amount;
                    if (index == plans.size() - 1) {
                        partQuantity = quantity;
                        quantity = BigDecimal.ZERO;
                    } else {
                        quantity = quantity.subtract(amount);
                    }
                    part.setQuantity(partQuantity.intValue());
                    part.setNetWeight(e.getNetWeight());
                    part.setArea(e.getArea() != null ? e.getArea() : BigDecimal.ZERO);
                    part.setRectangleArea(e.getRectangleArea() != null ? e.getRectangleArea() : BigDecimal.ZERO);
                    part.setRequireFactoryId(e.getFactoryCode());
                    part.setWidth(e.getWidth());
                    part.setLength(e.getLength());
                    if (e.getThickness() == null || e.getThickness().compareTo(BigDecimal.ZERO) == 0) {
                        part.setThickness(reqVo.getThickness());
                    } else {
                        part.setThickness(e.getThickness());
                    }
                    part.setPartMapUrl(mesPNG + e.getPngUrl());
                    part.setPlateCode(e.getPlateCode());
                    part.setSortingCount(0);// 分拣数量
                    part.setUniCode(plan.getUniMaterCode());
                    part.setSortState(0);
                    part.setOrderId(plan.getOrderId());
                    part.setWorkOrderCode(e.getWorkOrderCode());
                    part.setMesOrderCode(e.getMesOrderCode());
                    part.setMesPkgCode(e.getMesPkgCode());
                    part.setMesLineId(e.getLineId());
                    receiveParts.add(part);
                    if (index == plans.size() - 1) {
                        plan.setPlanFinishAmount(planFinishAmount.add(partQuantity));
                    } else {
                        plan.setPlanFinishAmount(planAmount);
                    }
                    plan.setConsumeStatus(1);
                    plan.setStatus(4);
                    plan.setErrorMsg("已回填数据。");
                    log.info("目标数据:{}", JsonUtils.toJsonString(plan));
                    sinoCamPushPlanMapper.updateById(plan);
                }
            }

            if (quantity.compareTo(BigDecimal.ZERO) > 0) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(e.getPartId());
                logNestExce.setQuantity(quantity.intValue());
                logNestExce.setNote("该零件套料数量比计划数量多：" + e.getPartId());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
            }

        }

        sinoCamReceiveNestPartMapper.insertBatchSomeColumn(receiveParts);
        for (SinoCamReceiveNestPart a : receiveParts) {
            log.info("insert-batch:{}", a.getId());
        }

    }

    @Transactional
    public void changePartInfoPlate(String plateCode) {
        // 先删除钢板上的零件信息
        List<SinoCamReceiveNestPart> nestPartList = sinoCamReceiveNestPartMapper.lambdaQuery().eq(SinoCamReceiveNestPart::getPlateCode, plateCode).list();
        if (CollUtil.isNotEmpty(nestPartList)) {
            List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery()
                    .in(SinoCamPushPlan::getNestPlanId, nestPartList.stream().map(SinoCamReceiveNestPart::getNestPlanId).collect(Collectors.toList())).list();
            Map<String, SinoCamPushPlan> pushPlanMap = pushPlanList.stream().collect(Collectors.toMap(SinoCamPushPlan::getNestPlanId, Function.identity()));

            for (SinoCamReceiveNestPart part : nestPartList) {
                SinoCamPushPlan pp = pushPlanMap.get(part.getNestPlanId());
                pp.setPlanFinishAmount(pp.getPlanFinishAmount().subtract(BigDecimal.valueOf(part.getQuantity())));
                pp.setConsumeStatus(0);
                sinoCamPushPlanMapper.updateById(pp);
            }
            for (SinoCamReceiveNestPart a : nestPartList) {
                sinoCamReceiveNestPartMapper.deleteMesNest(a.getId());
            }
        }

    }

    public List<String> fixChangeNestInfo(List<String> list) {
        List<String> res = new ArrayList<>();

        for (String plate : list) {
//            res.add("钢板号：" + plate);

            List<MesReceiveNestPartReqVo> plateNestInfo = apsMesFeign.getPlateNestInfo(plate);
            Map<String, List<MesReceiveNestPartReqVo>> collect = plateNestInfo.stream().collect(Collectors.groupingBy(MesReceiveNestPartReqVo::getPartId));
            Map<String, Integer> mesMap = new HashMap<>();
            for (String s : collect.keySet()) {
                int mesQuantity = collect.get(s).stream().mapToInt(MesReceiveNestPartReqVo::getQuantity).sum();
                mesMap.put(s, mesQuantity);
            }

            List<SinoCamReceiveNestPart> nestPartList = sinoCamReceiveNestPartMapper.lambdaQuery().eq(SinoCamReceiveNestPart::getPlateCode, plate).list();
            if (nestPartList.isEmpty()) {
                res.add("APS未接收到该钢板" + plate);
                continue;
            }
            Map<String, List<SinoCamReceiveNestPart>> collect1 = nestPartList.stream().collect(Collectors.groupingBy(SinoCamReceiveNestPart::getPartId));
            Map<String, Integer> apsMap = new HashMap<>();
            for (String s : collect1.keySet()) {
                int apsQuantity = collect1.get(s).stream().mapToInt(SinoCamReceiveNestPart::getQuantity).sum();
                apsMap.put(s, apsQuantity);
            }

            for (String s : mesMap.keySet()) {
                if (!apsMap.containsKey(s) && !s.contains("SMGZ") && !s.contains("SFZC") && !s.contains("063ZZ") && !s.contains("063DL")) {
                    res.add("MES中钢板" + plate + "零件" + s + "APS无");
                } else {
                    if (!Objects.equals(mesMap.get(s), apsMap.get(s))) {
                        if (!s.contains("SMGZ") && !s.contains("SFZC") && !s.contains("063ZZ") && !s.contains("063DL")) {
                            res.add("MES钢板" + plate + "零件" + s + "数量" + mesMap.get(s));
                        }
                    }
                }
            }
            for (String s : apsMap.keySet()) {
                if (!mesMap.containsKey(s) && !s.contains("SMGZ") && !s.contains("SFZC") && !s.contains("063ZZ") && !s.contains("063DL")) {
                    res.add("APS中钢板" + plate + "差" + s + "MES无");
                } else {
                    if (!Objects.equals(apsMap.get(s), mesMap.get(s))) {
                        if (!s.contains("SMGZ") && !s.contains("SFZC") && !s.contains("063ZZ") && !s.contains("063DL")) {
                            res.add("APS钢板" + plate + "零件" + s + "数量" + apsMap.get(s));
                        }
                    }
                }
            }
        }
        return res;
    }

    public List<SinoCamReceiveNestCheck> disListStream() {
        List<SinoCamReceiveNestCheck> list = sinoCamReceiveNestCheckMapper.lambdaQuery().list();
        // 去重一
//        List<SinoCamReceiveNestCheck> collect = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(SinoCamReceiveNestCheck::getNestId))), ArrayList::new));
        // 去重二
        Collection<SinoCamReceiveNestCheck> values = list.stream().collect(Collectors.toMap(e -> e.getNestId(), Function.identity(), (e1, e2) -> e1)).values();
        List<SinoCamReceiveNestCheck> collect = new ArrayList<>(values);

        return collect;
    }


    @Transactional(readOnly = true)
    @SneakyThrows
    public Workbook excel(Integer orderId) {
//        try(Workbook workbook = orderService.syncError(reqVo)){
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("同步错误");

        List<String> title = new ArrayList<>();
        title.add("零件名称");
        title.add("plmId");
        title.add("计划数量");
        title.add("完成数量");
        title.add("工序链");
        title.add("工序");
        title.add("工序计划数量");
        title.add("工序完成数量");

        sheet.setColumnWidth(11, 256 * 60);
        PoiUtils.title(sheet, title);
        List<ApsWorkOrder> apsWorkOrderList = apsWorkOrderMapper.lambdaQuery()
                .eq(ApsWorkOrder::getOrderId, orderId)
                .list();
        Map<Integer, ApsWorkOrder> apsWorkOrderMap = apsWorkOrderList.stream().collect(Collectors.toMap(e -> e.getId(), Function.identity()));

        List<ApsWorkDetail> apsWorkDetailList = apsWorkDetailMapper.lambdaQuery()
                .eq(ApsWorkDetail::getOrderId, orderId)
                .eq(ApsWorkDetail::getType, 2)
                .list();
        Map<Integer, List<ApsWorkDetail>> collect1 = apsWorkDetailList.stream().collect(Collectors.groupingBy(e -> apsWorkOrderMap.get(e.getApsWorkOrderId()).getBomId()));


        Map<Integer, ApsWorkOrder> collect = apsWorkOrderList.stream().collect(Collectors.toMap(ApsWorkOrder::getBomId, Function.identity(), (e1, e2) -> {
            e1.setOrderCount(e1.getOrderCount().add(e2.getOrderCount()));
            e1.setFinishCount(e1.getFinishCount().add(e2.getFinishCount()));
            return e1;
        }));

        int index = 1;

        List<ApsWorkOrder> values = new ArrayList<>(collect.values());
        values.sort(Comparator.comparing(ApsWorkOrder::getLevel).reversed());

        for (ApsWorkOrder entry : values) {

            String materName = entry.getMaterName();
            String plmId = entry.getPlmId();
            String woTotalCount = entry.getOrderCount().toPlainString();
            String woFinishCount = entry.getFinishCount().toPlainString();

            List<ApsWorkDetail> apsWorkDetailList1 = collect1.get(entry.getBomId());

            if (CollUtil.isEmpty(apsWorkDetailList1)) {
                int j = 0;

                Row row = sheet.createRow(index);
                Cell cell1 = row.createCell(j++);
                cell1.setCellValue(materName);

                Cell cell2 = row.createCell(j++);
                cell2.setCellValue(plmId);

                Cell cell3 = row.createCell(j++);
                cell3.setCellValue(woTotalCount);

                Cell cell4 = row.createCell(j++);
                cell4.setCellValue(woFinishCount);

                Cell cell5 = row.createCell(j++);
                cell5.setCellValue(entry.getWorkChain());
                index++;
            } else {
                Map<Integer, ApsWorkDetail> collect2 = apsWorkDetailList1.stream()
                        .collect(Collectors.toMap(ApsWorkDetail::getPhaseSeq, Function.identity(), (e1, e2) -> {
                            e1.setTotalCount(e1.getTotalCount().add(e2.getTotalCount()));
                            e1.setFinishCount(e1.getFinishCount().add(e2.getFinishCount()));
                            return e1;
                        }));


                List<Integer> collect3 = collect2.keySet().stream().sorted().collect(Collectors.toList());
                for (Integer seq : collect3) {
                    Row row = sheet.createRow(index);
                    int j = 0;

                    Cell cell1 = row.createCell(j++);
                    cell1.setCellValue(materName);

                    Cell cell2 = row.createCell(j++);
                    cell2.setCellValue(plmId);

                    Cell cell3 = row.createCell(j++);
                    cell3.setCellValue(woTotalCount);

                    Cell cell4 = row.createCell(j++);
                    cell4.setCellValue(woFinishCount);

                    Cell cell5 = row.createCell(j++);
                    cell5.setCellValue(entry.getWorkChain());

                    ApsWorkDetail apsWorkDetail = collect2.get(seq);

                    Cell cell6 = row.createCell(j++);
                    cell6.setCellValue(apsWorkDetail.getPhaseCode());

                    Cell cell7 = row.createCell(j++);
                    cell7.setCellValue(apsWorkDetail.getTotalCount().toPlainString());

                    Cell cell8 = row.createCell(j++);
                    cell8.setCellValue(apsWorkDetail.getTotalCount().toPlainString());
                    index++;
                }
            }


        }


//        Map

//        for (int i = 0; i < errorList.size(); i++) {
//            Row dataRow = sheet.createRow(i + 1);
////            Cell typeCell = dataRow.createCell(0);
////            Cell contentCell = dataRow.createCell(1);
////            typeCell.setCellValue(errorList.get(i).getErrorType());
////            contentCell.setCellValue(errorList.get(i).getErrorMessage());
//
//
//            PoiUtils.cells(dataRow,
//                    params.get(errorList.get(i).getErrorType()),
//                    errorList.get(i).getConstructNo(),
//                    errorList.get(i).getWorkOrderCode(),
//                    errorList.get(i).getMaterCode(),
//                    errorList.get(i).getMaterialName(),
//                    errorList.get(i).getPlmId(),
//                    errorList.get(i).getStandards(),
//                    errorList.get(i).getPartCount(),
//                    errorList.get(i).getPmCode(),
//                    errorList.get(i).getMaterialState(),
//                    errorList.get(i).getPaintCode(),
//                    errorList.get(i).getErrorMessage()
//            );
//        }

        return workbook;
    }

    @Transactional
    public void fixOrderMesInfo290(String orderCode) {
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().eq(SinoCamPushPlan::getProductId, orderCode).list();
        for (SinoCamPushPlan pushPlan : pushPlanList) {
            ApsWorkDetail apsWorkDetail = apsWorkDetailMapper.selectById(pushPlan.getNestPlanId());
            pushPlan.setApsOrderId(apsWorkDetail.getApsOrderId());
            HexagonPackagePush hexagonPackagePush = hexagonPackagePushMapper.lambdaQuery()
                    .eq(HexagonPackagePush::getApsOrderId, apsWorkDetail.getApsOrderId())
                    .eq(HexagonPackagePush::getOrderId, apsWorkDetail.getOrderId())
                    .one();
            pushPlan.setMesOrderCode(hexagonPackagePush.getMesOrderCode());
            pushPlan.setMesPkgCode(hexagonPackagePush.getPackageCode());
            sinoCamPushPlanMapper.updateById(pushPlan);
        }
    }

    @Transactional
    public void receiveMesPartOnly(MesReceiveNestPlateReqVo reqVo) {
        List<MesReceiveNestPartReqVo> partList = reqVo.getPart();
        for (MesReceiveNestPartReqVo part : partList) {
            MesNestPart p = new MesNestPart();
            p.setPlateCode(reqVo.getPlateCode());
            p.setNestId(reqVo.getNestId());
            p.setConstructNo(part.getConstructNo());
            p.setWorkOrderCode(part.getWorkOrderCode());
            p.setPackageCode(part.getMesPkgCode());
            p.setPartId(part.getPartId());
            p.setPartName(part.getPartName());
            p.setQuantity(part.getQuantity());
            p.setLength(part.getLength());
            p.setThickness(part.getThickness());
            p.setWidth(part.getWidth());
            p.setArea(part.getArea());
            p.setRectangleArea(part.getRectangleArea());
            p.setNetWeight(part.getNetWeight());
            p.setPngUrl(part.getPngUrl());
            p.setPath(part.getPath());
            p.setLineId(part.getLineId());
            mesNestPartMapper.insert(p);
        }
    }

    public void updatePlateNestStatusNew(String plateCode, boolean isCheck) {
        // isCheck true 默认状态，检查钢板锁定状态 flase 强制更新，钢板切割报工时调用

        Plate one = plateMapper.lambdaQuery().eq(Plate::getMaterCode, plateCode).one();
        if (one == null) {
            throw SyExceptionUtils.e("钢板信息为空：{}", plateCode);
        }

        String nestId = one.getNestId();

        List<Plate> plateList = plateMapper.lambdaQuery().eq(Plate::getNestId, nestId).list();

        if (isCheck) {
            List<String> qgPhaseList = projectConfig.getCuttingProcess();
            ApsWorkDetail qg = apsWorkDetailMapper.lambdaQuery()
                    .eq(ApsWorkDetail::getMaterNo, plateCode)
                    .in(ApsWorkDetail::getPhaseCode, qgPhaseList)
                    .eq(ApsWorkDetail::getType, 1)
                    .one();
            if (qg.getStatus() == 4) {
                throw SyExceptionUtils.e("此钢板已切割报工：{}", plateCode);
            }

            for (Plate p : plateList) {
                if (p.getNestLock() != 1) {
                    throw SyExceptionUtils.e("钢板未被套料锁定：{}", p.getMaterCode());
                }
            }
        }

        List<String> plateCodeList = plateList.stream().map(Plate::getMaterCode).distinct().collect(Collectors.toList());

        for (String str : plateCodeList) {
            ReceiveNestPlateReqVo plateVo = receiveNestInfoHand(str);

            log.info("修改套料结果:{}", plateVo.toString());
            LogApi logApi = logApiUtils.getReceiveLog("MES套料", "修改套料结果", "/sinoCam/updatePlateNestStatusNew");
            // JSON转换
            String s = JsonUtils.toJsonString(plateVo);
            log.info("修改MES套料结果:{}", s);
            Map<String, String> resVo = new HashMap<>();
            try {
                logApiUtils.setReqStr(logApi, s);

                ReceiveNestPlateReqVo nestInfoVo = handleNestResult(plateVo);
                clearPartInfoPlate(str);
                changeNestInfoHand(nestInfoVo);
                changeRecordHand(nestInfoVo);

                String userCode = SySecurityUtils.getUserCode();
                log.info("手动解锁钢板套料状态，钢板可以报工，操作人员：{}，钢板号：{}", userCode, str);

                String remark = "套料图号：" + plateVo.getNestId();
                logApiUtils.successAndSave(logApi, resVo, remark);

                try {
                    // 通知 MES 将钢板状态进行锁定
                    UpdateNxolpstatusVo dto = new UpdateNxolpstatusVo();
                    dto.setNxolnestixno(nestId);
                    apsMesFeign.lockNxolpstatus(dto);
                } catch (Exception e) {
                    e.getMessage();
                }

            } catch (Exception e) {
                e.printStackTrace();
                logApiUtils.errorAndSave(logApi, resVo, e.getMessage());
            }
        }

    }

    @SneakyThrows
    public ReceiveNestPlateReqVo receiveNestInfoHand(String plateCode) {

        ReceiveNestPlateReqVo plateVo = apsMesFeign.receiveNestInfo(plateCode);

//        String s = FileUtils.readFileToString(new File("D:\\soft\\nestInfo.txt"), "UTF-8");
//        ReceiveNestPlateReqVo plateVo = objectMapper.readValue(s, ReceiveNestPlateReqVo.class);

        if (ObjectUtils.isEmpty(plateVo)) {
            throw SyExceptionUtils.e("未获取到该钢板的套料结果：{}", plateCode);
        }

        return handleNestResult(plateVo);
    }

    public void clearPartInfoPlate(String plateCode) {
        Plate one = plateMapper.lambdaQuery().eq(Plate::getMaterCode, plateCode).one();

        if (one.getNestLock() == 2) {
            return ;
        }

        // 先删除钢板上的零件信息
        List<SinoCamReceiveNestPart> nestPartList = sinoCamReceiveNestPartMapper.lambdaQuery().eq(SinoCamReceiveNestPart::getPlateCode, plateCode).list();
        if (CollUtil.isNotEmpty(nestPartList)) {
            List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery()
                    .in(SinoCamPushPlan::getNestPlanId, nestPartList.stream().map(SinoCamReceiveNestPart::getNestPlanId).collect(Collectors.toList())).list();
            Map<String, SinoCamPushPlan> pushPlanMap = pushPlanList.stream().collect(Collectors.toMap(SinoCamPushPlan::getNestPlanId, Function.identity()));

            for (SinoCamReceiveNestPart part : nestPartList) {
                SinoCamPushPlan pp = pushPlanMap.get(part.getNestPlanId());
                pp.setPlanFinishAmount(pp.getPlanFinishAmount().subtract(BigDecimal.valueOf(part.getQuantity())));
                pp.setConsumeStatus(0);
                sinoCamPushPlanMapper.updateById(pp);
            }
            for (SinoCamReceiveNestPart a : nestPartList) {
                sinoCamReceiveNestPartMapper.deleteMesNest(a.getId());
            }
        }
        WorkDetailTask llTask = workDetailTaskMapper.lambdaQuery()
                .eq(WorkDetailTask::getPlmid, plateCode)
                .eq(WorkDetailTask::getType, 1)
                .eq(WorkDetailTask::getPhaseCode, WorkshopProp.LL_PHASE_CODE)
                .one();
        if (!ObjectUtils.isEmpty(llTask) && llTask.getStatus() == 3) {
            for (SinoCamReceiveNestPart nestPart : nestPartList) {
                ApsWorkDetail qgWrkDetail = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getId, nestPart.getNestPlanId()).one();
                ApsWorkDetail llApsWorkDetail  = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getApsWorkOrderId, qgWrkDetail.getApsWorkOrderId())
                        .eq(ApsWorkDetail::getType, 2)  .eq(ApsWorkDetail::getPhaseCode,WorkshopProp.LL_PHASE_CODE).last("  LIMIT 1 ").one();
                if(!org.apache.commons.lang3.ObjectUtils.isEmpty(llApsWorkDetail)){
                    //更新零件的计划信息
                    apsWorkDetailMapper.lambdaUpdate().eq(ApsWorkDetail::getId, llApsWorkDetail.getId())
                            .set(ApsWorkDetail::getUniqueCode, plateCode)
                            .set(ApsWorkDetail::getStatus, 3)
                            .set(org.apache.commons.lang3.ObjectUtils.isEmpty(llApsWorkDetail.getActualStartDateTime()),ApsWorkDetail::getActualStartDateTime, LocalDateTime.now())
                            .set(ApsWorkDetail::getActualEndDateTime, LocalDateTime.now())
                            .setSql("finish_count=finish_count-"+nestPart.getQuantity()).update();
                }
            }
        }
        WorkDetailTask yCTask = workDetailTaskMapper.lambdaQuery()
                .eq(WorkDetailTask::getPlmid, plateCode)
                .eq(WorkDetailTask::getType, 1)
                .eq(WorkDetailTask::getPhaseCode, WorkshopProp.YC_PHASE_CODE)
                .one();
        if (!ObjectUtils.isEmpty(yCTask) && yCTask.getStatus() == 3) {
            for (SinoCamReceiveNestPart nestPart : nestPartList) {
                ApsWorkDetail qgApsWorkDetail = apsWorkDetailMapper.lambdaQuery()
                        .eq(ApsWorkDetail::getId, nestPart.getNestPlanId())
                        .one();
                if(!ObjectUtils.isEmpty(qgApsWorkDetail)){
                    ApsWorkDetail ycWorkDetail = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getType, 2)
                            .eq(ApsWorkDetail::getApsWorkOrderId, qgApsWorkDetail.getApsWorkOrderId())
                            .eq(ApsWorkDetail::getPhaseCode, WorkshopProp.YC_PHASE_CODE).last(" LIMIT 1 ").one();

                    if(!ObjectUtils.isEmpty(ycWorkDetail)){
                        apsWorkDetailMapper.lambdaUpdate().eq(ApsWorkDetail::getId, ycWorkDetail.getId())
                                .set(ApsWorkDetail::getUniqueCode, plateCode)
                                .set(ApsWorkDetail::getStatus, 3)
                                .set(ObjectUtils.isEmpty(ycWorkDetail.getActualStartDateTime()),ApsWorkDetail::getActualStartDateTime, LocalDateTime.now())
                                .set(ApsWorkDetail::getActualEndDateTime, LocalDateTime.now())
                                .set(ycWorkDetail.getFinishCount().add(new BigDecimal(nestPart.getQuantity())).compareTo(ycWorkDetail.getTotalCount())>=0,ApsWorkDetail::getStatus, 4)
                                .setSql("finish_count=finish_count-"+nestPart.getQuantity()).update();
                    }
                }

            }

        }
        //删除报工记录
        List<WorkRecord> recordList = workRecordMapper.lambdaQuery().eq(WorkRecord::getPalletNumber, plateCode).eq(WorkRecord::getType, 2)
                .eq(WorkRecord::getPhaseCode, WorkshopProp.YC_PHASE_CODE).list();
        for (WorkRecord r : recordList) {
            workRecordMapper.deleteWithId(r.getId());
        }

        one.setNestLock(2);
        plateMapper.updateById(one);

    }

    public void changeNestInfoHand(ReceiveNestPlateReqVo reqVo) {

        LogNestExce logNestExce = new LogNestExce();

        // 查询钢板上零件的推送计划，先锁订单，再锁零件号
        List<ReceiveNestPartReqVo> partList = reqVo.getPart();

        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery()
                .in(SinoCamPushPlan::getProductId, partList.stream().map(ReceiveNestPartReqVo::getConstructNo).collect(Collectors.toList()))
                .in(SinoCamPushPlan::getPartId, partList.stream().map(ReceiveNestPartReqVo::getPartId).collect(Collectors.toList()))
                .orderByAsc(SinoCamPushPlan::getProcessingNo)
                .list();
        if (pushPlanList.isEmpty()) {
            logNestExce.setAppId("MES套料");
            logNestExce.setPlateCode(reqVo.getPlateCode());
            logNestExce.setConstructNo(null);
            logNestExce.setNestId(reqVo.getNestId());
            logNestExce.setPartId("ALL");
            logNestExce.setQuantity(0);
            logNestExce.setNote("未查询到该板零件的推送计划：" + reqVo.getPlateCode());
            logNestExce.setInfoState(0);
            logNestExceMapper.insert(logNestExce);
            return;
        }

        Optional<SinoCamPushPlan> min = pushPlanList.stream().min(Comparator.comparing(SinoCamPushPlan::getNeedDate));
        LocalDateTime needDate = min.get().getNeedDate();
        String needDateTime = needDate.format(DatePattern.NORM_DATETIME_FORMATTER);

        // 套料
        SinoCamReceiveNestNest nestNest = sinoCamReceiveNestNestMapper.lambdaQuery().eq(SinoCamReceiveNestNest::getNestId, reqVo.getNestId()).one();
        nestNest.setLength(reqVo.getLength());
        nestNest.setNestDate(reqVo.getNestDateTime().replace(".0", ""));
        nestNest.setChangeDate(reqVo.getChangeDateTime().replace(".0", ""));
        nestNest.setNester(reqVo.getNester());
        nestNest.setChanger(reqVo.getChanger());
        nestNest.setOptionId(reqVo.getGroupCode());
        nestNest.setRate(reqVo.getRate());
        nestNest.setWidth(reqVo.getWidth());
        nestNest.setNeedDate(needDateTime);
        LocalDateTime nowDateTime = LocalDateTime.now();
        String nowTime = nowDateTime.format(DatePattern.PURE_DATE_FORMATTER);
        nestNest.setBookSheet(nowTime);
        nestNest.setNestDxfUrl(reqVo.getDxfUrl());
        nestNest.setSplitGroupCode(reqVo.getGroupCode());
        nestNest.setReportPdfUrl(reqVo.getReportPdfUrl());
        nestNest.setCuttingProgramUrl(reqVo.getNestId());
        sinoCamReceiveNestNestMapper.updateById(nestNest);

        // 零件
        List<ReceiveNestPartReqVo> partListVo = reqVo.getPart();
        List<SinoCamReceiveNestPart> nestPartList = new ArrayList<>();

        int scId = nestNest.getSinoCamId();
        int scrnId = nestNest.getReceiveNestId();

        for (ReceiveNestPartReqVo e : partListVo) {

            if (!StringUtils.hasText(e.getMesOrderCode())) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(e.getPartId());
                logNestExce.setQuantity(e.getQuantity());
                logNestExce.setNote("该零件没有MES施工号：" + e.getPartId());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
                continue;
            }

            if (!StringUtils.hasText(e.getMesPkgCode())) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(e.getPartId());
                logNestExce.setQuantity(e.getQuantity());
                logNestExce.setNote("该零件没有MES包号：" + e.getPartId());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
                continue;
            }

            HexagonPackagePush hexagonPush = null;
            List<HexagonPackagePush> hexagonPackagePushList = hexagonPackagePushMapper.lambdaQuery()
                    .eq(HexagonPackagePush::getMesOrderCode, e.getMesOrderCode())
                    .eq(HexagonPackagePush::getPackageCode, e.getMesPkgCode())
                    .list();
            if (CollUtil.isNotEmpty(hexagonPackagePushList)) {
                if (hexagonPackagePushList.size() > 1) {
                    throw SyExceptionUtils.e("MES工单号和包号有重复：" + e.getMesOrderCode() + "_" + e.getPackageCode());
                }
                hexagonPush = hexagonPackagePushList.get(0);
            }

            if (hexagonPush == null) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(e.getPartId());
                logNestExce.setQuantity(e.getQuantity());
                logNestExce.setNote("该零件没有推送映射关系：" + e.getPartId());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
                continue;
            }

            List<SinoCamPushPlan> pushOneList = sinoCamPushPlanMapper.lambdaQuery()
                    .eq(SinoCamPushPlan::getApsOrderId, hexagonPush.getApsOrderId())
                    .eq(SinoCamPushPlan::getPath, e.getPath())
                    .eq(SinoCamPushPlan::getPartId, e.getPartId())
                    .list();
            if (CollUtil.isEmpty(pushOneList)) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(e.getPartId());
                logNestExce.setQuantity(1);
                logNestExce.setNote("零件计划为空：" + hexagonPush.getApsOrderId() + "#" + e.getPartId());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
            } else {
                if (pushOneList.size() > 1) {
                    logNestExce.setAppId("MES套料");
                    logNestExce.setPlateCode(reqVo.getPlateCode());
                    logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                    logNestExce.setNestId(reqVo.getNestId());
                    logNestExce.setPartId(e.getPartId());
                    logNestExce.setQuantity(1);
                    logNestExce.setNote("单包下零件计划不唯一：" + hexagonPush.getApsOrderId() + "#" + e.getPartId());
                    logNestExce.setInfoState(0);
                    logNestExceMapper.insert(logNestExce);
                } else {
                    SinoCamPushPlan pushOne = pushOneList.get(0);

                    SinoCamReceiveNestPart part = MkBeanUtils.copyProperties(e, SinoCamReceiveNestPart.class);
                    part.setSinoCamId(scId);
                    part.setReceiveNestId(scrnId);
                    part.setNestId(reqVo.getNestId());
                    part.setNestPlanId(pushOne.getNestPlanId());
                    part.setPartId(pushOne.getPartId());
                    part.setPartName(e.getPartName());
                    part.setQuantity(e.getQuantity());
                    part.setNetWeight(e.getNetWeight());
                    part.setArea(e.getArea() != null ? e.getArea() : BigDecimal.ZERO);
                    part.setRectangleArea(e.getRectangleArea() != null ? e.getRectangleArea() : BigDecimal.ZERO);
                    part.setRequireFactoryId(e.getFactoryCode());
                    part.setWidth(e.getWidth());
                    part.setLength(e.getLength());
                    if (e.getThickness() == null) {
                        part.setThickness(reqVo.getThickness());
                    } else {
                        part.setThickness(e.getThickness());
                    }
                    part.setPartMapUrl(mesPNG + e.getPngUrl());
                    part.setPlateCode(e.getPlateCode());
                    part.setSortingCount(0);// 分拣数量
                    part.setUniCode(pushOne.getUniMaterCode());
                    part.setSortState(0);

                    part.setOrderId(pushOne.getOrderId());
                    part.setWorkOrderCode(e.getWorkOrderCode());
                    part.setMesOrderCode(e.getMesOrderCode());
                    part.setMesPkgCode(e.getMesPkgCode());
                    part.setMesLineId(e.getLineId());

                    pushOne.setPlanFinishAmount(pushOne.getPlanFinishAmount().add(BigDecimal.valueOf(e.getQuantity())));
                    nestPartList.add(part);
                    pushOne.setStatus(4);
                    pushOne.setErrorMsg("已回填数据。");
                    sinoCamPushPlanMapper.updateById(pushOne);

                    if (pushOne.getPlanFinishAmount().compareTo(pushOne.getPlanAmount()) > 0) {
                        logNestExce.setAppId("MES套料");
                        logNestExce.setPlateCode(reqVo.getPlateCode());
                        logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                        logNestExce.setNestId(reqVo.getNestId());
                        logNestExce.setPartId(e.getPartId());
                        logNestExce.setQuantity(pushOne.getPlanFinishAmount().subtract(pushOne.getPlanAmount()).intValue());
                        logNestExce.setNote("该零件套料数量超计划，超了：" + pushOne.getPlanFinishAmount().subtract(pushOne.getPlanAmount()).intValue() + "个。");
                        logNestExce.setInfoState(0);
                        logNestExceMapper.insert(logNestExce);
                    }
                }
            }

        }
        if (CollUtil.isNotEmpty(nestPartList)) {
            sinoCamReceiveNestPartMapper.insertBatchSomeColumn(nestPartList);
        }

        log.info("零件:{}", JsonUtils.toJsonString(nestPartList));

        // 钢板
        SinoCamReceiveNestPlate nestPlate = sinoCamReceiveNestPlateMapper.lambdaQuery().eq(SinoCamReceiveNestPlate::getStockListNo, reqVo.getPlateCode()).one();
        nestPlate.setLength(reqVo.getLength());
        nestPlate.setWidth(reqVo.getWidth());
        nestPlate.setSideLength(reqVo.getSideLength());
        nestPlate.setRate(reqVo.getRate());
        nestPlate.setPngUrl(mesPNG + reqVo.getPngUrl());
        nestPlate.setNestArea(reqVo.getNxusedarea());
        sinoCamReceiveNestPlateMapper.updateById(nestPlate);

        log.info("钢板:{}", JsonUtils.toJsonString(nestPlate));

        // 余料
        List<ReceiveNestExcessReqVo> excessListVo = reqVo.getExcess();
        List<SinoCamReceiveNestExcess> nestExcessList = sinoCamReceiveNestExcessMapper.lambdaQuery().eq(SinoCamReceiveNestExcess::getStockListNo, reqVo.getPlateCode()).list();
        if (CollUtil.isNotEmpty(nestExcessList)) {
            for (SinoCamReceiveNestExcess vo : nestExcessList) {
                sinoCamReceiveNestExcessMapper.deleteMesNest(vo.getId());
            }
        }
        if (CollUtil.isNotEmpty(excessListVo)) {
            ReceiveNestExcessReqVo excessVo = excessListVo.get(0);
            SinoCamReceiveNestExcess excess = MkBeanUtils.copyProperties(excessVo, SinoCamReceiveNestExcess.class);
            excess.setSinoCamId(scId);
            excess.setReceiveNestId(scrnId);
            excess.setNestId(reqVo.getNestId());
            excess.setFactoryIdk("170");
            excess.setStockListNo(excessVo.getPlateCode());
            excess.setExMaterielId(excessVo.getExcessCode());
            excess.setTexture(excessVo.getTexture());
            excess.setNorm(excessVo.getThickness().toString());
            excess.setWidth(excessVo.getWidth());
            excess.setLength(excessVo.getLength());
            excess.setWeight(excessVo.getWeight());
            excess.setOutStock(0);
            sinoCamReceiveNestExcessMapper.insert(excess);

            log.info("余料:{}", JsonUtils.toJsonString(excess));
        }

        // 走刀
        List<ReceiveNestMoveReqVo> moveListVo = reqVo.getMove();
        List<SinoCamReceiveNestMove> moves = new ArrayList<>();
        List<SinoCamReceiveNestMove> nestMoveList = sinoCamReceiveNestMoveMapper.lambdaQuery().eq(SinoCamReceiveNestMove::getNestId, reqVo.getNestId()).list();
        if (CollUtil.isNotEmpty(nestMoveList)) {
            for (SinoCamReceiveNestMove vo : nestMoveList) {
                sinoCamReceiveNestMoveMapper.deleteMesNest(vo.getId());
            }
        }
        if (CollUtil.isNotEmpty(moveListVo)) {
            int totalTime = 0;
            for (ReceiveNestMoveReqVo vo : moveListVo) {
                SinoCamReceiveNestMove move = MkBeanUtils.copyProperties(vo, SinoCamReceiveNestMove.class);
                move.setSinoCamId(scId);
                move.setReceiveNestId(scrnId);
                move.setNestId(reqVo.getNestId());
                move.setCutLength(vo.getCutLength());
                move.setFactoryIdk(vo.getFactoryCode());
                move.setMoveTime(vo.getMoveTime());
                move.setMoveType(vo.getMoveType());
                move.setHoleCount(vo.getHoleCount());
                move.setHoleTime(vo.getHoleTime());
                move.setTotalHoleTime(vo.getTotalHoleTime());
                move.setCutRate(vo.getCutRate());
                move.setTotalCutTime(vo.getTotalCutTime());
                totalTime = totalTime + vo.getTotalCutTime();
                moves.add(move);
            }
            for (SinoCamReceiveNestMove a : moves) {
                a.setTotalCutTime(totalTime);
            }
            sinoCamReceiveNestMoveMapper.insertBatchSomeColumn(moves);
        } else {
            SinoCamReceiveNestMove move1 = new SinoCamReceiveNestMove();
            SinoCamReceiveNestMove move2 = new SinoCamReceiveNestMove();

            move1.setSinoCamId(scId);
            move1.setReceiveNestId(scrnId);
            move1.setNestId(reqVo.getNestId());
            move1.setCutLength(BigDecimal.valueOf(1));
            move1.setFactoryIdk("170");
            move1.setMoveTime(1);
            move1.setMoveType(1);
            move1.setHoleCount(1);
            move1.setHoleTime(1);
            move1.setTotalHoleTime(1);
            move1.setCutRate(BigDecimal.valueOf(1));
            move1.setTotalCutTime(1);
            sinoCamReceiveNestMoveMapper.insert(move1);

            move2.setSinoCamId(scId);
            move2.setReceiveNestId(scrnId);
            move2.setNestId(reqVo.getNestId());
            move2.setCutLength(BigDecimal.valueOf(1));
            move2.setFactoryIdk("170");
            move2.setMoveTime(1);
            move2.setMoveType(2);
            move2.setHoleCount(1);
            move2.setHoleTime(0);
            move2.setTotalHoleTime(0);
            move2.setCutRate(BigDecimal.valueOf(1));
            move2.setTotalCutTime(1);
            sinoCamReceiveNestMoveMapper.insert(move2);

            logNestExce.setAppId("MES套料");
            logNestExce.setPlateCode(reqVo.getPlateCode());
            logNestExce.setConstructNo(partListVo.get(0).getConstructNo());
            logNestExce.setNestId(reqVo.getNestId());
            logNestExce.setPartId(null);
            logNestExce.setQuantity(null);
            logNestExce.setNote("该钢板没有走刀信息！：" + reqVo.getPlateCode());
            logNestExce.setInfoState(0);
            logNestExceMapper.insert(logNestExce);
        }

        Map<String, String> fjGroup = new HashMap<>();
        fjGroup.put("1-1_HYQG_00", "1-1_RGFJ_00");
        fjGroup.put("1-2_JGQG_00", "1-2_ZDFJ_00");
        fjGroup.put("1-3_JGQG_00", "1-3_ZDFJ_00");

        // 钢板计划
        List<ApsWorkDetail> detailList = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getMaterNo, reqVo.getPlateCode()).list();
        for (ApsWorkDetail detail : detailList) {
            if ("JG".equals(detail.getPhaseCode()) || "HG".equals(detail.getPhaseCode())) {
                detail.setGroupCode(reqVo.getGroupCode());
                apsWorkDetailMapper.updateById(detail);
            }
            if ("FJ".equals(detail.getPhaseCode())) {
                detail.setGroupCode(fjGroup.get(reqVo.getGroupCode()));
                apsWorkDetailMapper.updateById(detail);
            }
        }

        // 钢板信息
        Plate plate = plateMapper.lambdaQuery().eq(Plate::getMaterCode, reqVo.getPlateCode()).one();
        SinoCamReceiveNestExcess nestExcess = sinoCamReceiveNestExcessMapper.lambdaQuery().eq(SinoCamReceiveNestExcess::getStockListNo, reqVo.getPlateCode()).one();
        BigDecimal weight = reqVo.getWeight();
        if (nestExcess != null) {
            weight = weight.subtract(nestExcess.getWeight());
        }
        plate.setLength(reqVo.getLength());
        plate.setWidth(reqVo.getWidth());
        plate.setWeight(reqVo.getWeight());
        plate.setNestWeight(weight.multiply(reqVo.getRate().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP)));
        plate.setNestRate(reqVo.getRate());
        plate.setNestingDrawing(mesPNG + reqVo.getPngUrl());
        plate.setNestLock(0);
        plateMapper.updateById(plate);

        // 钢板领料信息
        WmsPlatePick platePick = wmsPlatePickMapper.lambdaQuery().eq(WmsPlatePick::getMaterialCode, reqVo.getPlateCode()).one();
        platePick.setLength(reqVo.getLength());
        platePick.setNesting(mesPNG + reqVo.getPngUrl());
        platePick.setPlateUsage(reqVo.getRate());
        platePick.setPlateWeight(reqVo.getWeight());
        platePick.setWidth(reqVo.getWidth());
        wmsPlatePickMapper.updateById(platePick);

        // 钢板任务
        List<WorkDetailTask> taskList = workDetailTaskMapper.lambdaQuery().eq(WorkDetailTask::getMaterCode, reqVo.getPlateCode()).list();
        for (WorkDetailTask task : taskList) {
            task.setPartPath(mesPNG + reqVo.getPngUrl());
            task.setWeight(reqVo.getWeight());
            task.setLength(reqVo.getLength());
            task.setWidth(reqVo.getWidth());
            if ("YC".equals(task.getPhaseCode())) {
                task.setNextGroupCode(reqVo.getGroupCode());
            }
            if ("JG".equals(task.getPhaseCode()) || "HG".equals(task.getPhaseCode())) {
                task.setGroupCode(reqVo.getGroupCode());
            }
            workDetailTaskMapper.updateById(task);
        }

        // 钢板工序信息
        List<PlatePhase> platePhaseList = platePhaseMapper.lambdaQuery().eq(PlatePhase::getPlateCode, reqVo.getPlateCode()).list();
        List<SinoCamReceiveNestMove> nestMoves = sinoCamReceiveNestMoveMapper.lambdaQuery().eq(SinoCamReceiveNestMove::getNestId, reqVo.getNestId()).list();
        for (PlatePhase platePhase : platePhaseList) {
            if ("JG".equals(platePhase.getPhaseCode()) || "HG".equals(platePhase.getPhaseCode())) {
                if (CollUtil.isNotEmpty(nestMoves)) {
                    platePhase.setWorkTime(nestMoves.get(0).getTotalCutTime());
                } else {
                    platePhase.setWorkTime(0);
                }
                platePhase.setGroupCode(reqVo.getGroupCode());
                platePhaseMapper.updateById(platePhase);
            }
            if ("FJ".equals(platePhase.getPhaseCode())) {
                platePhase.setGroupCode(fjGroup.get(reqVo.getGroupCode()));
                platePhaseMapper.updateById(platePhase);
            }
        }

    }

    public void changeRecordHand(ReceiveNestPlateReqVo reqVo) {
        // 回填计划和报工

        String plateCode = reqVo.getPlateCode();

        List<SinoCamReceiveNestPart> nestParts = sinoCamReceiveNestPartMapper.lambdaQuery()
                .eq(SinoCamReceiveNestPart::getPlateCode, plateCode)
                .list();

        WorkDetailTask llTask = workDetailTaskMapper.lambdaQuery()
                .eq(WorkDetailTask::getPlmid, plateCode)
                .eq(WorkDetailTask::getType, 1)
                .eq(WorkDetailTask::getPhaseCode, WorkshopProp.LL_PHASE_CODE)
                .one();
        if (!ObjectUtils.isEmpty(llTask) && llTask.getStatus() == 3) {
            for (SinoCamReceiveNestPart nestPart : nestParts) {
                ApsWorkDetail qgWrkDetail = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getId, nestPart.getNestPlanId()).one();
                ApsWorkOrder workOrder = apsWorkOrderMapper.lambdaQuery().eq(ApsWorkOrder::getId, qgWrkDetail.getApsWorkOrderId()).one();
                if(workOrder.getStatus()<3){
                    workOrder.setStatus(3);
                    workOrder.setActualStartDateTime(LocalDateTime.now());
                    apsWorkOrderMapper.updateById(workOrder);
                }
                ApsWorkDetail llApsWorkDetail  = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getApsWorkOrderId, qgWrkDetail.getApsWorkOrderId())
                        .eq(ApsWorkDetail::getType, 2)  .eq(ApsWorkDetail::getPhaseCode,WorkshopProp.LL_PHASE_CODE).last("  LIMIT 1 ").one();
                if(!org.apache.commons.lang3.ObjectUtils.isEmpty(llApsWorkDetail)){
                    //更新零件的计划信息
                    apsWorkDetailMapper.lambdaUpdate().eq(ApsWorkDetail::getId, llApsWorkDetail.getId())
                            .set(ApsWorkDetail::getUniqueCode, plateCode)
                            .set(org.apache.commons.lang3.ObjectUtils.isEmpty(llApsWorkDetail.getActualStartDateTime()),ApsWorkDetail::getActualStartDateTime, LocalDateTime.now())
                            .set(ApsWorkDetail::getActualEndDateTime, LocalDateTime.now())
                            .setSql("finish_count=finish_count+"+nestPart.getQuantity()).update();
                    llApsWorkDetail=  partUtilService.updateDetailState(llApsWorkDetail.getId());
                }

            }
        }
        WorkDetailTask yCTask = workDetailTaskMapper.lambdaQuery()
                .eq(WorkDetailTask::getPlmid, plateCode)
                .eq(WorkDetailTask::getType, 1)
                .eq(WorkDetailTask::getPhaseCode, WorkshopProp.YC_PHASE_CODE)
                .one();
        if (!ObjectUtils.isEmpty(yCTask) && yCTask.getStatus() == 3) {
            Map<String, String> map = new HashMap<>();
            for (SinoCamReceiveNestPart nestPart : nestParts) {
                ApsWorkDetail qgApsWorkDetail = apsWorkDetailMapper.lambdaQuery()
                        .eq(ApsWorkDetail::getId, nestPart.getNestPlanId())
                        .one();
                if(!ObjectUtils.isEmpty(qgApsWorkDetail)){
                    ApsWorkDetail ycWorkDetail = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getType, 2)
                            .eq(ApsWorkDetail::getApsWorkOrderId, qgApsWorkDetail.getApsWorkOrderId())
                            .eq(ApsWorkDetail::getPhaseCode, WorkshopProp.YC_PHASE_CODE).last(" LIMIT 1 ").one();

                    if(map.get("constructNo_"+qgApsWorkDetail.getOrderId())==null){
                        Order one = orderMapper.lambdaQuery().eq(Order::getId, qgApsWorkDetail.getOrderId()).one();
                        map.put("constructNo_"+qgApsWorkDetail.getOrderId(),one.getConstructNo());
                    }

                    if(!ObjectUtils.isEmpty(ycWorkDetail)){
                        log.info(ycWorkDetail.getId()+"修改前数据"+JsonUtils.toJsonString(ycWorkDetail));
                        apsWorkDetailMapper.lambdaUpdate().eq(ApsWorkDetail::getId, ycWorkDetail.getId())
                                .set(ApsWorkDetail::getUniqueCode, reqVo.getPlateCode())
                                .set(ObjectUtils.isEmpty(ycWorkDetail.getActualStartDateTime()),ApsWorkDetail::getActualStartDateTime, LocalDateTime.now())
                                .set(ApsWorkDetail::getActualEndDateTime, LocalDateTime.now())
                                .set(ycWorkDetail.getFinishCount().add(new BigDecimal(nestPart.getQuantity())).compareTo(ycWorkDetail.getTotalCount())>=0,ApsWorkDetail::getStatus, 4)
                                .setSql("finish_count=finish_count+"+nestPart.getQuantity()).update();
                        partUtilService.updateDetailState(ycWorkDetail.getId());
                    }else{
                        ycWorkDetail=new ApsWorkDetail();
                        ycWorkDetail.setMaterNo(nestPart.getPartId());
                    }
                    partUtilService.complatePartReport(map.get("constructNo_"+qgApsWorkDetail.getOrderId()), ycWorkDetail.getGroupCode(),  ycWorkDetail.getGroupCode(), 2, 2,
                            ycWorkDetail.getPlmId(),  WorkshopProp.YC_PHASE_CODE, reqVo.getPlateCode(), nestPart.getQuantity(), 0,
                            SySecurityUtils.getUserCode(), null, ycWorkDetail.getId(), null, null, reqVo.getPlateCode());


                }

            }
        }
    }

    public void receiveMesNew(ReceiveNestPlateReqVo plateVo) {

        ReceiveNestPlateReqVo vo = handleNestResult(plateVo);

        hexagonNestOldUtils.receiveMesNew(vo);

        try {
            // 通知 MES 将钢板状态进行锁定
            UpdateNxolpstatusVo dto = new UpdateNxolpstatusVo();
            dto.setNxolnestixno(plateVo.getNestId());
            apsMesFeign.lockNxolpstatus(dto);
        } catch (Exception e) {
            e.getMessage();
        }
    }

    public ReceiveNestPlateReqVo handleNestResult(ReceiveNestPlateReqVo plateVo) {
        try {
            List<ReceiveNestPartReqVo> partListVo = plateVo.getPart();
            List<ReceiveNestExcessReqVo> excessListVo = plateVo.getExcess();
            List<ReceiveNestMoveReqVo> moveListVo = plateVo.getMove();

            plateVo.setFactoryCode("170");
            plateVo.setStoreCode("170");
            BigDecimal plateWeight = PlateWeightUtils.getPlateWeight(plateVo.getLength(), plateVo.getWidth(), plateVo.getThickness());
            plateVo.setWeight(plateWeight);
            plateVo.setDxfUrl(NestInfoChangeUtil.addDxf(plateVo.getNestId()));
            plateVo.setCuttingProgramUrl(plateVo.getNestId());
            plateVo.setPngUrl(NestInfoChangeUtil.replacePng(plateVo.getPngUrl(), ".png"));
            plateVo.setThickness(plateVo.getThickness() != null ? plateVo.getThickness() : BigDecimal.ZERO);
            plateVo.setSideLength(plateVo.getSideLength() != null ? plateVo.getSideLength() : BigDecimal.ZERO);

            for (ReceiveNestPartReqVo vo : partListVo) {
                vo.setFactoryCode("170");
                vo.setPngUrl(NestInfoChangeUtil.replacePng(vo.getPngUrl(), ".png"));
                vo.setThickness(vo.getThickness() != null ? vo.getThickness() : plateVo.getThickness());
                vo.setArea(vo.getArea() != null ? vo.getArea() : BigDecimal.ZERO);
                vo.setRectangleArea(vo.getRectangleArea() != null ? vo.getRectangleArea() : BigDecimal.ZERO);
            }

            if (CollUtil.isNotEmpty(excessListVo)) {
                ReceiveNestExcessReqVo excessVo = excessListVo.get(0);
                excessVo.setFactoryCode("170");
                excessVo.setTexture(excessVo.getTexture() != null ? excessVo.getTexture() : plateVo.getTexture());
                excessVo.setThickness(excessVo.getThickness() != null ? excessVo.getThickness() : plateVo.getThickness());
                excessVo.setWeight(excessVo.getWeight() != null ? excessVo.getWeight() : BigDecimal.ZERO);
            }

            if (CollUtil.isNotEmpty(moveListVo)) {
                for (int i = 0; i < moveListVo.size(); i++) {
                    ReceiveNestMoveReqVo vo = moveListVo.get(i);
                    vo.setCutRate(vo.getCutRate() != null ? vo.getCutRate() : BigDecimal.ZERO);
                    vo.setFactoryCode("170");
                    if (vo.getMoveCode().equals("切割路径")) {
                        vo.setMoveType(1);
                    } else if (vo.getMoveCode().equals("空程路径")) {
                        vo.setMoveType(2);
                    } else {
                        moveListVo.remove(i);
                        i--;
                    }
                }
            }

            plateVo.setPart(partListVo);
            plateVo.setExcess(excessListVo);
            plateVo.setMove(moveListVo);

            return plateVo;
        } catch (Exception e) {
            e.printStackTrace();
            LogNestExce logNestExce = new LogNestExce();
            logNestExce.setAppId("MES套料");
            logNestExce.setPlateCode(plateVo.getPlateCode());
            logNestExce.setConstructNo(null);
            logNestExce.setNestId(plateVo.getNestId());
            logNestExce.setPartId(null);
            logNestExce.setQuantity(0);
            logNestExce.setNote("该钢板套料信息处理异常：" + plateVo.getPlateCode());
            logNestExce.setInfoState(0);
            logNestExceMapper.insert(logNestExce);
            throw SyExceptionUtils.e("套料信息处理异常：{}", plateVo.getPlateCode());
        }
    }

    @SneakyThrows
    public void receiveNestNewTest() {
        String s = FileUtils.readFileToString(new File("D:\\soft\\nestInfo.txt"), "UTF-8");
        ReceiveNestPlateReqVo plateVo = objectMapper.readValue(s, ReceiveNestPlateReqVo.class);
        receiveMesNew(plateVo);
    }

    public List<String> checkPlateChange(String s) {
        List<String> list = new ArrayList<>();
        String[] split = s.split(",");
        for (String string : split) {
            SinoCamReceiveNestPlate plate = sinoCamReceiveNestPlateMapper.lambdaQuery().eq(SinoCamReceiveNestPlate::getStockListNo, string).one();
            SinoCamReceiveNestNest nest = sinoCamReceiveNestNestMapper.lambdaQuery().eq(SinoCamReceiveNestNest::getNestId, plate.getNestId()).one();

            ReceiveNestPlateReqVo plateVo = apsMesFeign.receiveNestInfo(string);

            String changeDate = nest.getChangeDate();
            String changeDateVo = plateVo.getChangeDateTime();

            if (!changeDate.equals(changeDateVo)) {
                list.add(string);
            }
        }
        return list;
    }

    public void receiveNestIdInfo(SinoCamNestIdReqVo reqVo) {
        SinoCamReceiveNestCheck check = sinoCamReceiveNestCheckMapper.lambdaQuery()
                .eq(SinoCamReceiveNestCheck::getNestId, reqVo.getNestId())
                .eq(SinoCamReceiveNestCheck::getCheckState, 0)
                .one();
        if (!ObjectUtils.isEmpty(check)) {
            check.setCheckState(3);
            sinoCamReceiveNestCheckMapper.updateById(check);
        }

        SinoCamReceiveNestCheck newCheck = new SinoCamReceiveNestCheck();
        newCheck.setNestId(reqVo.getNestId());
        newCheck.setCheckState(0);
        sinoCamReceiveNestCheckMapper.insert(newCheck);
    }

    public void addPlanPath(BaseIdReqVo reqVo) {
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().eq(SinoCamPushPlan::getOrderId, reqVo.getId()).list();
        List<ApsWorkDetail> apsWorkDetailList = apsWorkDetailMapper.lambdaQuery().in(ApsWorkDetail::getId, pushPlanList.stream().map(SinoCamPushPlan::getNestPlanId).collect(Collectors.toList())).list();
        Map<Integer, ApsWorkDetail> apsWorkDetailMap = apsWorkDetailList.stream().collect(Collectors.toMap(ApsWorkDetail::getId, Function.identity()));

        List<ApsWorkOrder> apsWorkOrderList = apsWorkOrderMapper.lambdaQuery().eq(ApsWorkOrder::getOrderId, reqVo.getId()).list();
        Map<Integer, ApsWorkOrder> apsWorkOrderMap = apsWorkOrderList.stream().collect(Collectors.toMap(ApsWorkOrder::getId, Function.identity()));

        List<HexagonPackagePush> hexPushList = hexagonPackagePushMapper.lambdaQuery().eq(HexagonPackagePush::getOrderId, reqVo.getId()).list();
        Map<Integer, HexagonPackagePush> hexPushMap = hexPushList.stream().collect(Collectors.toMap(HexagonPackagePush::getApsOrderId, Function.identity()));

        for (SinoCamPushPlan plan : pushPlanList) {
            ApsWorkDetail detail = apsWorkDetailMap.get(Integer.valueOf(plan.getNestPlanId()));
            ApsWorkOrder child = apsWorkOrderMap.get(detail.getApsWorkOrderId());
            HexagonPackagePush hexPush = hexPushMap.get(child.getApsOrderId());
            int id = child.getId();
            String path = "";
            while (true) {
                ApsWorkOrder current = apsWorkOrderMap.get(id);
                if (current.getPid() == null) {
                    break;
                }
                ApsWorkOrder parent = apsWorkOrderMap.get(current.getPid());
                path = "→" + parent.getPlmId() + path;
                id = parent.getId();
            }
            plan.setPath(hexPush.getPackageCode() + path);
            sinoCamPushPlanMapper.updateById(plan);
        }

    }

    public void checkNestExist(BaseIdReqVo reqVo) {
        List<SinoCamReceiveNestPart> nestPartList = sinoCamReceiveNestPartMapper.lambdaQuery().eq(SinoCamReceiveNestPart::getNestPlanId, reqVo.getId()).list();
        List<String> plateCodeList = nestPartList.stream().map(SinoCamReceiveNestPart::getPlateCode).distinct().collect(Collectors.toList());
        for (String p : plateCodeList) {
            ReceiveNestPlateReqVo vo = apsMesFeign.checkNestPlate(p);
            if (ObjectUtils.isEmpty(vo)) {
                clearNestResultInfoPlate(p);

                LogNestExce logNestExce = new LogNestExce();
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(p);
                logNestExce.setConstructNo(p);
                logNestExce.setNestId(p);
                logNestExce.setPartId(p);
                logNestExce.setQuantity(1);
                logNestExce.setNote("钢板套料结果删除。");
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
            }
        }
    }

}
